--------------------
-- /START Options --
--------------------
-- This option disables most of IWD2:EE's functionality / engine patches, only leaving the widescreen and FPS uncap code
-- enabled, as well as some very minor convenience patches. This is intended for debugging the vanilla game with IEex.
IEex_Vanilla = false
------------------
-- /END Options --
------------------

function IEex_Reload()

	IEex_AssertThread(IEex_Thread.Async, true)

	dofile("override/IEex_IWD2_State.lua")

	IEex_Helper_SetBridge("IEex_NeedSyncTick", "val", 1)
	while IEex_Helper_GetBridge("IEex_NeedSyncTick", "val") == 1 do
		-- Spin until sync state is reloaded
		-- Need sleep call so this thread doesn't (effectively) keep IEex_NeedSyncTick locked
		IEex_Helper_Sleep(1)
	end
	IEex_Helper_SynchronizedBridgeOperation("IEex_ReloadListeners", function()
		IEex_ReloadListeners = IEex_Helper_ReadDataFromBridgeNL("IEex_ReloadListeners")
		IEex_Helper_ClearBridgeNL("IEex_ReloadListeners")
		local limit = #IEex_ReloadListeners
		for i = 1, limit, 1 do
			local funcName = IEex_ReloadListeners[i]
			_G[IEex_ReloadListeners[i]]()
		end
	end)
end

function IEex_Extern_SyncTick()
	dofile("override/IEex_IWD2_State.lua")
	IEex_Helper_SetBridge("IEex_NeedSyncTick", "val", 0)
end

function IEex_AddReloadListener(funcName)
	IEex_Helper_SynchronizedBridgeOperation("IEex_ReloadListeners", function()
		IEex_AppendBridgeNL("IEex_ReloadListeners", funcName)
	end)
end

function IEex_ReaddReloadListener(funcName)
	IEex_AppendBridgeNL("IEex_ReloadListeners", funcName)
end

function IEex_FetchString(strref)

	local resultPtr = IEex_Malloc(0x4)
	IEex_Call(0x427B60, {strref, resultPtr}, nil, 0x8)

	local toReturn = IEex_ReadString(IEex_ReadDword(resultPtr))
	IEex_Call(0x7FCC1A, {}, resultPtr, 0x0)
	IEex_Free(resultPtr)

	return toReturn
end

---------------------
-- Specific States --
---------------------

dofile("override/IEex_TRA.lua")
dofile("override/IEex_WEIDU.lua")
if not IEex_Vanilla then
	dofile("override/IEex_INI.lua")
end

dofile("override/IEex_Bridge.lua")
dofile("override/IEex_IWD2_Common_State.lua")
dofile("override/IEex_Core_State.lua")
dofile("override/IEex_Debug_State.lua")
dofile("override/IEex_Action_State.lua")
dofile("override/IEex_Creature_State.lua")
dofile("override/IEex_Opcode_State.lua")
dofile("override/IEex_Key_State.lua")
dofile("override/IEex_Gui_State.lua")
dofile("override/IEex_Render_State.lua")
dofile("override/IEex_Resource_State.lua")
dofile("override/IEex_Projectile_State.lua")
dofile("override/IEex_StartupFixes_State.lua")
dofile("override/IEex_Dev_State.lua")
dofile("override/IEex_FakeInputRoutine.lua")
dofile("override/IEex_UncapFPS.lua")




if not IEex_Vanilla then
	for module, tf in pairs(IEex_Modules) do
		if tf then
			dofile("override/" .. module .. ".lua")
		end
	end
end

-----------------------------------
-- Common Engine Structures Util --
-----------------------------------

function IEex_CString_Set(CString, newString)
	local newStringMem = IEex_WriteStringAuto(newString)
	-- CString_operator_equ_<char_const_ptr>
	IEex_Call(0x7FCD57, {newStringMem}, CString, 0x0)
	IEex_Free(newStringMem)
end

----------------
-- Spell List --
----------------

IEex_CasterType = {
	["Bard"] = 1,
	["Cleric"] = 2,
	["Druid"] = 3,
	["Paladin"] = 4,
	["Ranger"] = 5,
	["Sorcerer"] = 6,
	["Wizard"] = 7,
	["Domain"] = 8,
	["Innate"] = 9,
	["Song"] = 10,
	["Shape"] = 11,
}

IEex_CasterClassToType = {
	[2] = 1,
	[3] = 2,
	[4] = 3,
	[7] = 4,
	[8] = 5,
	[10] = 6,
	[11] = 7,
}

IEex_CasterTypeToClass = {
	[1] = 2,
	[2] = 3,
	[3] = 4,
	[4] = 7,
	[5] = 8,
	[6] = 10,
	[7] = 11,
	[8] = 3,
	[9] = 0,
	[10] = 0,
	[11] = 0,
}

function IEex_SetSpellInfo(actorID, casterType, spellLevel, resref, memorizedCount, castableCount)
	if not IEex_IsSprite(actorID, true) then return end
	local memMod = memorizedCount
	local castMod = castableCount

	local typeInfo = IEex_FetchSpellInfo(actorID, {casterType})
	local levelFill = typeInfo and typeInfo[casterType][spellLevel][3] or nil
	if levelFill then
		for _, entry in ipairs(levelFill) do
			if entry.resref == resref then
				memMod = memorizedCount - entry.memorizedCount
				castMod = castableCount - entry.castableCount
				break
			end
		end
	end
	IEex_AlterSpellInfo(actorID, casterType, spellLevel, resref, memMod, castMod)

end

function IEex_AlterSpellInfo(actorID, casterType, spellLevel, resref, memorizeMod, castableMod)
	if not IEex_IsSprite(actorID, true) then return end
	if casterType < 1 or casterType > 11 then
		local message = "[IEex_AlterSpellInfo] Critical Caller Error: casterType out of bounds - got "..casterType.."; valid range includes [1,11]"
		print(message)
		IEex_MessageBox(message)
		return
	end
	local isSorcererType = false
	if casterType == 1 or casterType == 6 then
		isSorcererType = true
	end
	local levelCheck = function(lower, higher)
		if spellLevel < lower or spellLevel > higher then
			local message = "[IEex_AlterSpellInfo] Critical Caller Error: spellLevel out of bounds - got "..spellLevel.." for type "..casterType.."; valid range includes ["..lower..","..higher.."]"
			print(message)
			IEex_MessageBox(message)
			return false
		end
		return true
	end

	if casterType <= 8 then
		if not levelCheck(1, 9) then return end
	else
		if not levelCheck(1, 1) then return end
	end

	local share = IEex_GetActorShare(actorID)

	local normal = function(casterType)
		return 0x4284 + (casterType - 1) * 0x100, IEex_LISTSPLL_Reverse
	end

	local switch = {
		[1]  = normal,
		[2]  = normal,
		[3]  = normal,
		[4]  = normal,
		[5]  = normal,
		[6]  = normal,
		[7]  = normal,
		[8]  = function(t) return 0x4984, IEex_LISTSPLL_Reverse end,
		[9]  = function(t) return 0x4A84, IEex_LISTINNT_Reverse end,
		[10] = function(t) return 0x4AA0, IEex_LISTSONG_Reverse end,
		[11] = function(t) return 0x4ABC, IEex_LISTSHAP_Reverse end,
	}

	local offset, list = switch[casterType](casterType)
	local baseTypeAddress = share + offset
	local address = baseTypeAddress + (spellLevel - 1) * 0x1C
	local memorizedCount = IEex_ReadDword(address + 0x14)
	local sorcererCastableCount = IEex_ReadDword(address + 0x18)
	if isSorcererType and resref == "" then

		memorizedCount = memorizedCount + memorizeMod
		if memorizedCount < 0 then
			memorizedCount = 0
		end

		sorcererCastableCount = sorcererCastableCount + castableMod
		if sorcererCastableCount < 0 then
			sorcererCastableCount = 0
		elseif sorcererCastableCount > memorizedCount then
			sorcererCastableCount = memorizedCount
		end
		IEex_WriteDword(address + 0x14, memorizedCount)
		IEex_WriteDword(address + 0x18, sorcererCastableCount)
		for i = 0, 8, 1 do
			local quickSlotData = share + 0x360C + 0x3C * i
			if IEex_CasterClassToType[IEex_ReadByte(quickSlotData + 0x36, 0x0)] == casterType and IEex_ReadByte(quickSlotData + 0x37, 0x0) == spellLevel then
				IEex_WriteWord(quickSlotData + 0x18, sorcererCastableCount)
				if sorcererCastableCount > 0 then
					IEex_WriteByte(quickSlotData + 0x3A, 0)
				else
					IEex_WriteByte(quickSlotData + 0x3A, 1)
				end
			end
		end
	end
	local id = list[resref]
	if not id and not isSorcererType then
		local message = "[IEex_AlterSpellInfo] Critical Caller Error: resref \""..resref.."\" not present in corresponding master spell-list 2DA"
		print(message)
		--IEex_MessageBox(message)
		return
	end
	if not isSorcererType or resref ~= "" then
		local ptrMem = IEex_Malloc(0x10)
		IEex_WriteDword(ptrMem, id)
		IEex_WriteDword(ptrMem + 0x4, memorizeMod)
		IEex_WriteDword(ptrMem + 0x8, castableMod)
		IEex_WriteDword(ptrMem + 0xC, 0x0)

		IEex_Call(0x725950, {
			ptrMem + 0xC,
			ptrMem + 0x8,
			ptrMem + 0x4,
			ptrMem
		}, address, 0x0)

		IEex_Free(ptrMem)
		if casterType <= 8 then
			for i = 0, 8, 1 do
				local quickSlotData = share + 0x360C + 0x3C * i
				if IEex_CasterClassToType[IEex_ReadByte(quickSlotData + 0x36, 0x0)] == casterType and IEex_ReadLString(quickSlotData + 0x20, 8) == resref then
					local currentEntryBase = IEex_ReadDword(address + 0x4)
					local pEndEntry = IEex_ReadDword(address + 0x8)
					while currentEntryBase ~= pEndEntry do
						if IEex_ReadDword(currentEntryBase) == id then
							local castableCount = IEex_ReadDword(currentEntryBase + 0x8)
							IEex_WriteWord(quickSlotData + 0x18, castableCount)
							if castableCount > 0 then
								IEex_WriteByte(quickSlotData + 0x3A, 0)
							else
								IEex_WriteByte(quickSlotData + 0x3A, 1)
							end
						end
						currentEntryBase = currentEntryBase + 0x10
					end
				end
			end
		else
			for i = 0, 8, 1 do
				local quickSlotData = share + 0x38DC + 0x3C * i
				if IEex_ReadLString(quickSlotData + 0x20, 8) == resref then
					local currentEntryBase = IEex_ReadDword(address + 0x4)
					local pEndEntry = IEex_ReadDword(address + 0x8)
					while currentEntryBase ~= pEndEntry do
						if IEex_ReadDword(currentEntryBase) == id then
							local castableCount = IEex_ReadDword(currentEntryBase + 0x8)
							IEex_WriteWord(quickSlotData + 0x18, castableCount)
							if castableCount > 0 then
								IEex_WriteByte(quickSlotData + 0x3A, 0)
							else
								IEex_WriteByte(quickSlotData + 0x3A, 1)
							end
						end
						currentEntryBase = currentEntryBase + 0x10
					end
				end
			end
		end
	elseif isSorcererType and resref == "" then
		local currentEntryBase = IEex_ReadDword(address + 0x4)
		local pEndEntry = IEex_ReadDword(address + 0x8)
		while currentEntryBase ~= pEndEntry do
			local castableCount = IEex_ReadDword(currentEntryBase + 0x8)
			castableCount = castableCount + castableMod
			if castableCount < 0 then
				castableCount = 0
			end
			IEex_WriteDword(currentEntryBase + 0x8, castableCount)
			currentEntryBase = currentEntryBase + 0x10
		end
	end
	if casterType <= 8 then
		local maxActiveLevelAddress = baseTypeAddress + 0xFC
		if IEex_ReadDword(maxActiveLevelAddress) < spellLevel and (memorizeMod > 0 or castableMod > 0) then
			IEex_WriteDword(maxActiveLevelAddress, spellLevel)
		end
	end

end

function IEex_FetchSpellInfo(actorID, casterTypes)
	if not IEex_IsSprite(actorID, true) then return {} end
	for _, casterType in ipairs(casterTypes) do
		if casterType < 1 or casterType > 11 then
			local message = "[IEex_FetchSpellInfo] Critical Caller Error: casterType out of bounds - got "..casterType.."; valid range includes [1,11]"
			print(message)
			IEex_MessageBox(message)
			return
		end
	end

	local toReturn = {}
	local share = IEex_GetActorShare(actorID)

	local dataFromEntry = function(address, t)
		return {
			["resref"] = t[IEex_ReadDword(address)],
			["memorizedCount"] = IEex_ReadDword(address + 0x4),
			["castableCount"] = IEex_ReadDword(address + 0x8),
		}
	end

	local genLevel = function(address, t)
		local levelFill = {}
		local currentEntryBase = IEex_ReadDword(address + 0x4)
		local pEndEntry = IEex_ReadDword(address + 0x8)
		while currentEntryBase ~= pEndEntry do
			table.insert(levelFill, dataFromEntry(currentEntryBase, t))
			currentEntryBase = currentEntryBase + 0x10
		end
		return levelFill
	end

	local typeFill = function(currentLevelBase, casterType)
		local typeFill = {}
		for level = 1, 9, 1 do
			local levelFill = genLevel(currentLevelBase, IEex_LISTSPLL)
			table.insert(typeFill, {IEex_ReadDword(currentLevelBase + 0x14), IEex_ReadDword(currentLevelBase + 0x18), levelFill})
			currentLevelBase = currentLevelBase + 0x1C
		end
		toReturn[casterType] = typeFill
	end

	local levelFill = function(currentLevelBase, casterType, t)
		local typeFill = {}
		local levelFill = genLevel(currentLevelBase, t)
		table.insert(typeFill, levelFill)
		toReturn[casterType] = typeFill
	end

	local normal = function(casterType)
		typeFill(share + 0x4284 + (casterType - 1) * 0x100, casterType)
	end

	local switch = {
		[1]  = normal,
		[2]  = normal,
		[3]  = normal,
		[4]  = normal,
		[5]  = normal,
		[6]  = normal,
		[7]  = normal,
		[8]  = function(type) typeFill(share + 0x4984, type) end,
		[9]  = function(type) levelFill(share + 0x4A84, type, IEex_LISTINNT) end,
		[10] = function(type) levelFill(share + 0x4AA0, type, IEex_LISTSONG) end,
		[11] = function(type) levelFill(share + 0x4ABC, type, IEex_LISTSHAP) end,
	}

	for _, casterType in ipairs(casterTypes) do
		switch[casterType](casterType)
	end

	return toReturn

end

function IEex_GetSpellNameRef(spellRES)
	local nameRef = 0
	local resWrapper = IEex_DemandRes(spellRES, "SPL")
	if resWrapper:isValid() then
		local spellData = resWrapper:getData()
		nameRef = IEex_ReadDword(spellData + 0x8)
	end
	resWrapper:free()
	return nameRef
end

------------------------
-- Actor Manipulation --
------------------------

function IEex_SetActorScript(actorID, level, resref)
	if not IEex_IsSprite(actorID, true) then return end
	IEex_ApplyEffectToActor(actorID, {
		["opcode"] = 82,
		["target"] = 1,
		["parameter2"] = level,
		["timing"] = 9,
		["resource"] = resref,
		["source_id"] = actorID,
	})
end

-- Directly applies an effect to a sprite based on the args table.
function IEex_ApplyEffectToSprite(sprite, args)

	if sprite <= 0 then return end

	local writeType = {
		["BYTE"]   = 0,
		["WORD"]   = 1,
		["DWORD"]  = 2,
		["RESREF"] = 3,
	}

	local writeTypeFunc = {
		[writeType.BYTE]   = IEex_WriteByte,
		[writeType.WORD]   = IEex_WriteWord,
		[writeType.DWORD]  = IEex_WriteDword,
		[writeType.RESREF] = function(address, arg) IEex_WriteLString(address, arg, 0x8) end,
	}

	local argFailType = {
		["ERROR"]   = 0,
		["DEFAULT"] = 1,
	}

	local writeArgs = function(address, writeDefs)
		for _, writeDef in ipairs(writeDefs) do
			local argKey = writeDef[1]
			local arg = args[argKey]
			if not arg then
				if writeDef[4] == argFailType.DEFAULT then
					arg = writeDef[5]
				else
					IEex_Error(argKey.." must be defined!")
				end
			end
			writeTypeFunc[writeDef[3]](address + writeDef[2], arg)
		end
	end

	local Item_effect_st = IEex_Malloc(0x30)
	writeArgs(Item_effect_st, {
		{ "opcode",        0x0,  writeType.WORD,   argFailType.ERROR        },
		{ "target",        0x2,  writeType.BYTE,   argFailType.DEFAULT, 1   },
		{ "power",         0x3,  writeType.BYTE,   argFailType.DEFAULT, 0   },
		{ "parameter1",    0x4,  writeType.DWORD,  argFailType.DEFAULT, 0   },
		{ "parameter2",    0x8,  writeType.DWORD,  argFailType.DEFAULT, 0   },
		{ "timing",        0xC,  writeType.BYTE,   argFailType.DEFAULT, 0   },
		{ "resist_dispel", 0xD,  writeType.BYTE,   argFailType.DEFAULT, 0   },
		{ "duration",      0xE,  writeType.DWORD,  argFailType.DEFAULT, 0   },
		{ "probability1",  0x12, writeType.BYTE,   argFailType.DEFAULT, 100 },
		{ "probability2",  0x13, writeType.BYTE,   argFailType.DEFAULT, 0   },
		{ "resource",      0x14, writeType.RESREF, argFailType.DEFAULT, ""  },
		{ "dicenumber",    0x1C, writeType.DWORD,  argFailType.DEFAULT, 0   },
		{ "dicesize",      0x20, writeType.DWORD,  argFailType.DEFAULT, 0   },
		{ "savingthrow",   0x24, writeType.DWORD,  argFailType.DEFAULT, 0   },
		{ "savebonus",     0x28, writeType.DWORD,  argFailType.DEFAULT, 0   },
		{ "special",       0x2C, writeType.DWORD,  argFailType.DEFAULT, 0   },
	})

	local source = IEex_Malloc(0x8)
	IEex_WriteDword(source + 0x0, args["source_x"] or -1)
	IEex_WriteDword(source + 0x4, args["source_y"] or -1)

	local target = IEex_Malloc(0x8)
	IEex_WriteDword(target + 0x0, args["target_x"] or -1)
	IEex_WriteDword(target + 0x4, args["target_y"] or -1)

	-- CGameEffect::DecodeEffect(Item_effect_st *effect, CPoint *source, int sourceID, CPoint *target)
	local CGameEffect = IEex_Call(0x48C800, {
		target,
		args["source_id"] or -1,
		source,
		Item_effect_st,
	}, nil, 0x10)

	IEex_Free(Item_effect_st)
	IEex_Free(source)
	IEex_Free(target)

	writeArgs(CGameEffect, {
		{ "sectype",           0x4C, writeType.DWORD,  argFailType.DEFAULT, 0  },
		{ "parameter3",        0x5C, writeType.DWORD,  argFailType.DEFAULT, 0  },
		{ "parameter4",        0x60, writeType.DWORD,  argFailType.DEFAULT, 0  },
		{ "parameter5",        0x64, writeType.DWORD,  argFailType.DEFAULT, 0  },
		{ "vvcresource",       0x6C, writeType.RESREF, argFailType.DEFAULT, "" },
		{ "resource2",         0x74, writeType.RESREF, argFailType.DEFAULT, "" },
		{ "restype",           0x8C, writeType.DWORD,  argFailType.DEFAULT, 0  },
		{ "parent_resource",   0x90, writeType.RESREF, argFailType.DEFAULT, "" },
		{ "resource_flags",    0x98, writeType.DWORD,  argFailType.DEFAULT, 0  },
		{ "impact_projectile", 0x9C, writeType.DWORD,  argFailType.DEFAULT, 0  },
		{ "sourceslot",        0xA0, writeType.DWORD,  argFailType.DEFAULT, -1 },
		{ "effvar",            0xA4, writeType.RESREF, argFailType.DEFAULT, "" },
		{ "casterlvl",         0xC4, writeType.DWORD,  argFailType.DEFAULT, 1  },
		{ "spell_penetration", 0xC8, writeType.DWORD,  argFailType.DEFAULT, 0  },
		{ "effect_identifier", 0xD0, writeType.DWORD,  argFailType.DEFAULT, 0  },
		{ "internal_flags",    0xD4, writeType.DWORD,  argFailType.DEFAULT, 0  },
	})
	-- CGameSprite::AddEffect(CGameSprite *this, CGameEffect *pEffect, char list, int noSave, int immediateResolve)
	IEex_Call(IEex_ReadDword(IEex_ReadDword(sprite) + 0x78), {1, 0, 1, CGameEffect}, sprite, 0x0)
end

function IEex_ApplyEffectToActor(actorID, args)
	IEex_ApplyEffectToSprite(IEex_GetActorShare(actorID), args)
end

function IEex_ApplyResref(resref, actorID)
	if not IEex_IsSprite(actorID, true) then return end
	local share = IEex_GetActorShare(actorID)

	local resrefMem = IEex_Malloc(#resref + 1)
	IEex_WriteString(resrefMem, resref)

	IEex_Call(IEex_Label("IEex_ApplyResref"), {resrefMem, share}, nil, 0x0)
	IEex_Free(resrefMem)

end

function IEex_SetActorName(actorID, strref)
	if not IEex_IsSprite(actorID, true) then return end
	local share = IEex_GetActorShare(actorID)
	IEex_WriteDword(share + 0x5A4, strref)
end

function IEex_SetActorTooltip(actorID, strref)
	if not IEex_IsSprite(actorID, true) then return end
	local share = IEex_GetActorShare(actorID)
	IEex_WriteDword(share + 0x5A8, strref)
end

-------------------
-- Actor Details --
-------------------

function IEex_IsActorSolelySelected(actorID)
	local pGame = IEex_GetGameData()
	return IEex_ReadDword(pGame + 0x3896) == 1 and IEex_ReadDword(IEex_ReadDword(pGame + 0x388E) + 0x8) == actorID
end

function IEex_CanSpriteUseItem(sprite, resref)
	local CItem = IEex_DemandCItemResref(resref)
	local junkPtr = IEex_Malloc(0x4)
	-- CInfGame_CheckIfSpriteCanUseItem
	local result = IEex_Call(0x5B9D20, {0x0, junkPtr, CItem, sprite}, IEex_GetGameData(), 0x0)
	IEex_Free(junkPtr)
	IEex_DumpCItem(CItem)
	return result == 1
end

function IEex_CheckActorLOS(actorID, pointX, pointY)
	local share = IEex_GetActorShare(actorID)
	if share <= 0 then return false end
	local area = IEex_ReadDword(share + 0x12)

	local actorX, actorY = IEex_GetActorLocation(actorID)
	local points = IEex_Malloc(0x10)
	IEex_WriteDword(points + 0x0, actorX)
	IEex_WriteDword(points + 0x4, actorY)
	IEex_WriteDword(points + 0x8, pointX)
	IEex_WriteDword(points + 0xC, pointY)

	local terrainTable = IEex_Call(IEex_ReadDword(IEex_ReadDword(share) + 0x9C), {}, share, 0x0)
	local toReturn = IEex_Call(0x46A820, {1, terrainTable, points + 0x8, points}, area, 0x0)

	IEex_Free(points)
	return toReturn == 1
end

function IEex_CheckActorLOSObject(actorID, targetID)
	local targetX, targetY = IEex_GetActorLocation(targetID)
	return IEex_CheckActorLOS(actorID, targetX, targetY)
end

function IEex_GetSpriteName(sprite)
	-- CGameSprite::GetName()
	if not IEex_IsObjectSprite(sprite, true) then return "" end
	local CString = IEex_Call(0x71F760, {}, sprite, 0x0)
	return IEex_ReadString(IEex_ReadDword(CString))
end

function IEex_GetActorName(actorID)
	-- CGameSprite::GetName()
	if not IEex_IsSprite(actorID, true) then return "" end
	local CString = IEex_Call(0x71F760, {}, IEex_GetActorShare(actorID), 0x0)
	return IEex_ReadString(IEex_ReadDword(CString))
end

function IEex_GetActorTooltip(actorID)
	if not IEex_IsSprite(actorID, true) then return "" end
	local share = IEex_GetActorShare(actorID)
	local nameStrref = IEex_ReadDword(share + 0x5A8)
	return IEex_FetchString(nameStrref)
end

ex_class_base_attack_table = {"BAATFGT", "BAATNFG", "BAATNFG", "BAATNFG", "BAATFGT", "BAATMKU", "BAATFGT", "BAATFGT", "BAATNFG", "BAATMAG", "BAATMAG"}
function IEex_GetActorBaseAttackBonus(actorID, fixMonkAttackBonus)
	if not IEex_IsSprite(actorID, true) then return 0 end
	local creatureData = IEex_GetActorShare(actorID)
	local baseAttackBonus = IEex_ReadSignedByte(creatureData + 0x5EC, 0x0)
	local monkAttackBonusDisabled = false
	local hasOtherClasses = false
	local monkLevel = IEex_GetActorStat(actorID, 101)
	if monkLevel > 0 then
		if IEex_GetActorStat(actorID, 96) > 0 or IEex_GetActorStat(actorID, 97) > 0 or IEex_GetActorStat(actorID, 98) > 0 or IEex_GetActorStat(actorID, 99) > 0 or IEex_GetActorStat(actorID, 100) > 0 or IEex_GetActorStat(actorID, 102) > 0 or IEex_GetActorStat(actorID, 103) > 0 or IEex_GetActorStat(actorID, 104) > 0 or IEex_GetActorStat(actorID, 105) > 1 or IEex_GetActorStat(actorID, 106) > 1 then
			monkAttackBonusDisabled = true
			hasOtherClasses = true
		end
		if IEex_ReadByte(creatureData + 0x4BA4, 0x0) ~= 10 then
			monkAttackBonusDisabled = true
		end
		IEex_IterateActorEffects(actorID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
			if theopcode == 288 and theparameter2 == 241 then
				if thespecial ~= 6 then
					monkAttackBonusDisabled = true
					if (thespecial == 1 and (theparameter1 ~= 67 or not ex_elven_chainmail_counts_as_unarmored)) or thespecial == 3 or (thespecial >= 4 and ex_special_monk_weapon_types[theparameter1] == nil) then
						fixMonkAttackBonus = false
					end
				end
			end
		end)
	end
--[[
	if monkAttackBonusDisabled and not fixMonkAttackBonus and not hasOtherClasses then
		baseAttackBonus = baseAttackBonus + tonumber(IEex_2DAGetAtStrings("BAATNFG", "BASE_ATTACK", tostring(monkLevel))) - tonumber(IEex_2DAGetAtStrings("BAATMKU", "BASE_ATTACK", tostring(monkLevel)))
	elseif fixMonkAttackBonus and hasOtherClasses then
		baseAttackBonus = baseAttackBonus + tonumber(IEex_2DAGetAtStrings("BAATMKU", "BASE_ATTACK", tostring(monkLevel))) - tonumber(IEex_2DAGetAtStrings("BAATNFG", "BASE_ATTACK", tostring(monkLevel)))
	end
--]]
	if not monkAttackBonusDisabled or fixMonkAttackBonus then
		baseAttackBonus = baseAttackBonus + tonumber(IEex_2DAGetAtStrings("BAATMKU", "BASE_ATTACK", tostring(monkLevel))) - tonumber(IEex_2DAGetAtStrings("BAATNFG", "BASE_ATTACK", tostring(monkLevel)))
	end
	if bit.band(IEex_ReadByte(creatureData + 0x89F, 0x0), 0x1) > 0 then
		if IEex_ReadByte(creatureData + 0x24, 0x0) <= 30 then
			baseAttackBonus = 0
		end
		for i = 1, 11, 1 do
			local classLevel = IEex_ReadByte(creatureData + 0x626 + i, 0x0)
			if classLevel > 0 then
				baseAttackBonus = baseAttackBonus + tonumber(IEex_2DAGetAtStrings(ex_class_base_attack_table[i], "BASE_ATTACK", tostring(classLevel)))
			end
		end
	end
	return baseAttackBonus
end

function IEex_GetActorArmorClass(actorID)
	if not IEex_IsSprite(actorID, true) then return {0, 0, 0, 0, 0} end
	local creatureData = IEex_GetActorShare(actorID)
	local armorClass = IEex_ReadSignedWord(creatureData + 0x5E2, 0x0)
	if bit.band(IEex_ReadDword(creatureData + 0x75C), 0x10000) > 0 then
		armorClass = armorClass + 1
	end
	local slashingAC = IEex_GetActorStat(actorID, 6)
	local piercingAC = IEex_GetActorStat(actorID, 5)
	local bludgeoningAC = IEex_GetActorStat(actorID, 3)
	local missileAC = IEex_GetActorStat(actorID, 4)
	local dexterityBonus = math.floor((IEex_GetActorStat(actorID, 40) - 10) / 2)
	local wisdomBonus = math.floor((IEex_GetActorStat(actorID, 39) - 10) / 2)
	local armorBonus = 0
	local deflectionBonus = 0
	local shieldBonus = 0
	local barkskinBonus = 0
	local armorType = 0
	local hasShield = false
	IEex_IterateActorEffects(actorID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter1 = IEex_ReadDword(eData + 0x1C)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
		if theopcode == 288 and theparameter2 == 241 then
			if theparameter1 >= 60 and theparameter1 <= 68 then
				armorType = theparameter1
			elseif thespecial == 3 then
				hasShield = true
			end
		elseif theopcode == 0 then
			if theparameter2 == 0 then
				armorClass = armorClass + theparameter1
			elseif theparameter2 == 1 and theparameter1 > armorBonus then
				armorBonus = theparameter1
			elseif theparameter2 == 2 and theparameter1 > deflectionBonus then
				deflectionBonus = theparameter1
			elseif theparameter2 == 1 and theparameter1 > shieldBonus then
				shieldBonus = theparameter1
			end
		elseif theopcode == 415 then
			local thecasterlvl = IEex_ReadByte(eData + 0xC8, 0x0)
			if thecasterlvl < 6 and barkskinBonus < 3 then
				barkskinBonus = 3
			elseif thecasterlvl >= 6 and thecasterlvl < 12 and barkskinBonus < 4 then
				barkskinBonus = 4
			elseif thecasterlvl >= 12 and barkskinBonus < 5 then
				barkskinBonus = 5
			end
		end
	end)
	local maxDexBonus = 99
	if ex_armor_penalties[armorType] ~= nil then
		maxDexBonus = ex_armor_penalties[armorType][2]
		if maxDexBonus < dexterityBonus then
			dexterityBonus = maxDexBonus
		end
	end
	if IEex_GetActorSpellState(actorID, 1) and deflectionBonus < 2 then
		deflectionBonus = 2
	end
	if IEex_GetActorSpellState(actorID, 55) and deflectionBonus < 5 then
		deflectionBonus = 5
	end
	if IEex_GetActorSpellState(actorID, 30) and deflectionBonus < 6 then
		deflectionBonus = 6
	end
	local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
	if bit.band(stateValue, 0x8000) > 0 then
		armorClass = armorClass + 4
	end
	if bit.band(stateValue, 0x10000) > 0 then
		armorClass = armorClass - 2
	end
	if bit.band(stateValue, 0x40000) > 0 then
		armorClass = armorClass - 2
	else
		armorClass = armorClass + dexterityBonus
	end

	armorClass = armorClass + armorBonus
	armorClass = armorClass + deflectionBonus
	armorClass = armorClass + shieldBonus
	armorClass = armorClass + barkskinBonus
	if IEex_GetActorStat(actorID, 101) > 0 and armorType == 0 and hasShield == false then
		armorClass = armorClass + wisdomBonus
	end
	for i = 1, 5, 1 do
		if IEex_GetActorSpellState(actorID, 80 + i) then
			armorClass = armorClass + i
		end
	end
	if IEex_GetActorSpellState(actorID, 70) then
		armorClass = armorClass + 4
	end
	return {armorClass, slashingAC, piercingAC, bludgeoningAC, missileAC}
end

-- Returns the sprite's current modal state, or 0 if the sprite is invalid
function IEex_GetSpriteModalState(sprite)
	if not IEex_IsObjectSprite(sprite) then return 0 end
	return IEex_ReadByte(sprite + 0x4C53)
end

-- Returns the actor's current modal state, or 0 if the actor is invalid
function IEex_GetActorModalState(actorID)
	return IEex_GetSpriteModalState(IEex_GetActorShare(actorID))
end

-- Returns the sprite's current bard song index (from LISTSONG.2DA), or 0 if the sprite is invalid.
--   Note: This is only valid if the sprite is currently in the bard song modal state.
function IEex_GetSpriteCurrentBardSongIndex(sprite)
	if not IEex_IsObjectSprite(sprite) then return 0 end
	return IEex_ReadByte(sprite + 0x3D42)
end

-- Returns the actor's current bard song index (from LISTSONG.2DA), or 0 if the actor is invalid.
--   Note: This is only valid if the actor is currently in the bard song modal state.
function IEex_GetActorCurrentBardSongIndex(actorID)
	return IEex_GetSpriteCurrentBardSongIndex(IEex_GetActorShare(actorID))
end

-- Returns the resref associated with the given bard song index (from LISTSONG.2DA), or "" if the index is invalid.
function IEex_BardSongIndexToResref(bardSongIndex)
	local pGame = IEex_GetGameData()
	local resrefArray = pGame + 0x4C08
	if bardSongIndex >= IEex_ReadDword(resrefArray + 0x4) then return "" end
	return IEex_ReadLString(IEex_ReadDword(resrefArray) + 0x8 * bardSongIndex, 8)
end

-- Return the specified stat of the actor (from STATS.IDS).
function IEex_GetActorStat(actorID, statID)
	if not IEex_IsSprite(actorID, true) then return 0 end
	local share = IEex_GetActorShare(actorID)
	local bAllowEffectListCall = IEex_ReadDword(share + 0x72A4) == 1
	local activeStats = share + (bAllowEffectListCall and 0x920 or 0x1778)
	if statID == 2 then
		return IEex_GetActorArmorClass(actorID)[1]
	elseif statID > 106 and ex_stat_offset[statID] ~= nil then
		local specialReadSize = ex_stat_offset[statID][2]
		local statValue = 0
		if specialReadSize == 1 then
			statValue = IEex_ReadSignedByte(share + ex_stat_offset[statID][1], 0x0)
		elseif specialReadSize == 2 then
			statValue = IEex_ReadSignedWord(share + ex_stat_offset[statID][1], 0x0)
		elseif specialReadSize == 4 then
			statValue = IEex_ReadDword(share + ex_stat_offset[statID][1])
		end
		return statValue
--[[
	elseif statID == 253 then
		if IEex_Helper_GetBridge("IEex_EnlargedAnimation", actorID) ~= nil then
			return 1
		else
			return 0
		end
--]]
	else
		return IEex_Call(0x446DD0, {statID}, activeStats, 0x0)
	end

end
ex_ability_score_opcode = {[36] = {44, 4}, [38] = {19, 7}, [39] = {49, 8}, [40] = {15, 5}, [41] = {10, 6}, [42] = {6, 9}, }
-- Return the specified stat of the actor (from STATS.IDS), but ignore the cap of 40 for ability scores.
function IEex_GetActorFullStat(actorID, statID)
	if not IEex_IsSprite(actorID, true) then return 0 end
	local normalStatValue = IEex_GetActorStat(actorID, statID)
	if statID < 36 or statID > 42 then
		return normalStatValue
	else
		local abilityScoreIndex = statID - 37
		if abilityScoreIndex == -1 then
			abilityScoreIndex = 0
		end
		local share = IEex_GetActorShare(actorID)
		local fullStatValue = IEex_ReadByte(share + 0x802 + abilityScoreIndex, 0x0)
		local maxStatBonus = -65536
		IEex_IterateActorEffects(actorID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thespecial = IEex_ReadDword(eData + 0x48)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			if theopcode == ex_ability_score_opcode[statID][1] then
				if theparameter2 == 0 then
					if theparameter1 > maxStatBonus then
						maxStatBonus = theparameter1
					end
				elseif theparameter2 == 1 then
					fullStatValue = theparameter1
				elseif theparameter2 == 2 then
					fullStatValue = math.floor(fullStatValue * theparameter1 / 100)
				end
			elseif theopcode == 78 and theparameter2 == ex_ability_score_opcode[statID][2] then
				fullStatValue = fullStatValue - theparameter1
			elseif theopcode == 500 and theresource == "MEMODSTA" and thespecial == statID then
				if theparameter2 == 0 then
					fullStatValue = fullStatValue + theparameter1
				elseif theparameter2 == 1 then
					fullStatValue = theparameter1
				elseif theparameter2 == 2 then
					fullStatValue = math.floor(fullStatValue * theparameter1 / 100)
				end
			end
		end)
		if maxStatBonus > -65536 then
			fullStatValue = fullStatValue + maxStatBonus
		end
		if fullStatValue < 0 then
			fullStatValue = 0
		elseif fullStatValue > ex_full_ability_score_cap then
			fullStatValue = ex_full_ability_score_cap
		end
		return fullStatValue
	end
end

function IEex_GetActorBaseStat(actorID, statID)
	local share = IEex_GetActorShare(actorID)
	local baseStats = {[36] = IEex_ReadByte(share + 0x802, 0x0), [38] = IEex_ReadByte(share + 0x803, 0x0), [39] = IEex_ReadByte(share + 0x804, 0x0), [40] = IEex_ReadByte(share + 0x805, 0x0), [41] = IEex_ReadByte(share + 0x806, 0x0), [42] = IEex_ReadByte(share + 0x807, 0x0), }

	if IEex_GetActorSpellState(actorID, 188) then
		IEex_IterateActorEffects(actorID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 188 and bit.band(thesavingthrow, 0x20000) == 0 then
				baseStats = {[36] = IEex_ReadByte(eData + 0x44, 0x0), [38] = IEex_ReadByte(eData + 0x47, 0x0), [39] = IEex_ReadByte(eData + 0x48, 0x0), [40] = IEex_ReadByte(eData + 0x45, 0x0), [41] = IEex_ReadByte(eData + 0x46, 0x0), [42] = IEex_ReadByte(eData + 0x49, 0x0), }
			end
		end)
	end
	return baseStats[statID]
end

-- Returns true if the actor has any of the specified states (from STATE.IDS).
-- For example, IEex_GetActorState(targetID, 0x28) returns true if targetID is helpless or stunned.
function IEex_GetActorState(actorID, state)
	if not IEex_IsSprite(actorID, true) then return false end
	local share = IEex_GetActorShare(actorID)
	local stateValue = bit.bor(IEex_ReadDword(share + 0x5BC), IEex_ReadDword(share + 0x920))
	return ((state == 0 and stateValue == 0) or bit.band(stateValue, state) ~= 0)
end

-- Returns true if the actor has the specified spell state (from SPLSTATE.IDS).
function IEex_GetActorSpellState(actorID, spellStateID)
	if not IEex_IsSprite(actorID, true) then return false end
--[[
	IEex_IterateActorEffects(actorID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		if theopcode == 288 and theparameter2 == spellStateID then
			return true
		end
	end)
--]]
	local bitsetStruct = IEex_Malloc(0x8)
	local spellStateStart = IEex_Call(0x4531A0, {}, IEex_GetActorShare(actorID), 0x0) + 0xEC
	IEex_Call(0x45E380, {spellStateID, bitsetStruct}, spellStateStart, 0x0)
	local spellState = bit.extract(IEex_Call(0x45E390, {}, bitsetStruct, 0x0), 0, 0x8)
	IEex_Free(bitsetStruct)
	return spellState == 1
end

-- Returns the actor's location.
function IEex_GetActorLocation(actorID)
	local share = IEex_GetActorShare(actorID)
	if share <= 0 then return -1, -1 end
	return IEex_ReadDword(share + 0x6), IEex_ReadDword(share + 0xA)
end

-- Returns the location the actor is moving to.
function IEex_GetActorDestination(actorID)
	if not IEex_IsSprite(actorID, true) then return -1, -1 end
	local share = IEex_GetActorShare(actorID)
	return IEex_ReadDword(share + 0x556E), IEex_ReadDword(share + 0x5572)
end

-- Returns the creature the actor is targeting with their current action.
function IEex_GetActorTarget(actorID)
	if not IEex_IsSprite(actorID, true) then return 0 end
	local share = IEex_GetActorShare(actorID)
	return IEex_ReadDword(share + 0x4BE)
end

-- Returns the coordinates of the point the actor is targeting with their
--  current action.
function IEex_GetActorTargetPoint(actorID)
	if not IEex_IsSprite(actorID, true) then return -1, -1 end
	local share = IEex_GetActorShare(actorID)
	local targetX = IEex_ReadDword(share + 0x540)
	local targetY = IEex_ReadDword(share + 0x544)
	local targetID = IEex_GetActorTarget(actorID)
	if targetID > 0 then
		targetX, targetY = IEex_GetActorLocation(targetID)
	end
	return targetX, targetY
end

function IEex_GetActorTooltip(actorID)
	if not IEex_IsSprite(actorID, true) then return "" end
	local share = IEex_GetActorShare(actorID)
	local nameStrref = IEex_ReadDword(share + 0x5A8)
	return IEex_FetchString(nameStrref)
end

-- Returns the object's current action struct, or nil if the object is invalid
function IEex_GetObjectCurrentAction(CGameAIBase)
	if not IEex_IsObjectAIBase(CGameAIBase) then return nil end
	return CGameAIBase + 0x476
end

-- Returns the actor's current action struct, or nil if the actor is invalid
function IEex_GetActorCurrentAction(actorID)
	return IEex_GetObjectCurrentAction(IEex_GetActorShare(actorID))
end

-- Returns the object's current action id (from ACTION.IDS), or 0 if the object is invalid
function IEex_GetObjectCurrentActionID(CGameAIBase)
	if not IEex_IsObjectAIBase(CGameAIBase) then return 0 end
	return IEex_ReadWord(CGameAIBase + 0x476)
end

-- Returns the actor's current action id (from ACTION.IDS), or 0 if the actor is invalid
function IEex_GetActorCurrentActionID(actorID)
	return IEex_GetObjectCurrentActionID(IEex_GetActorShare(actorID))
end

-- Returns the sprite's current action id (from ACTION.IDS), or 0 if the sprite is invalid.
-- In some instances IEex trickery is used to override the creature's current action id with a custom value.
-- This function returns the real value, as set by the engine.
function IEex_GetSpriteRealCurrentActionID(sprite)
	if not IEex_IsObjectSprite(sprite, true) then return 0 end
	local actionID = IEex_GetObjectCurrentActionID(sprite)
	return actionID ~= 0 and IEex_Helper_GetBridge("IEex_GameObjectData", IEex_GetActorIDShare(sprite), "realActionID") or 0
end

-- Returns true if the given action id is a standard spell-cast action
function IEex_IsActionIDSpellCast(actionID)
	return actionID == 31 or actionID == 95 or actionID == 113 or actionID == 114 or actionID == 191 or actionID == 192
end

-- Returns true if the given action id is a standard item-use action
function IEex_IsActionIDItemUse(actionID)
	return actionID == 34 or actionID == 97
end

-- Returns true if the given action id is a standard attack action
function IEex_IsActionIDAttack(actionID)
	return actionID == 3 or actionID == 94 or actionID == 98 or actionID == 105 or actionID == 134
end

function IEex_GetObjectUseItemSlot(share)
	local actionID = IEex_ReadWord(share + 0x476, 0x0)
	local spellRES = ""
	if actionID == 34 or actionID == 97 then
		spellRES = IEex_ReadString(IEex_ReadDword(share + 0x538))
		if spellRES == "" then
			local spellIDS = IEex_ReadWord(share + 0x52C, 0x0)
			if IEex_SpellIDSPrefix[math.floor(spellIDS / 1000)] ~= nil then
				spellRES = IEex_SpellIDSPrefix[math.floor(spellIDS / 1000)] .. (spellIDS % 1000)
			end
		end
	end
	return spellRES
end

-- Returns the resref of the spell the object is currently casting.
IEex_SpellIDSPrefix = {[1] = "SPPR", [2] = "SPWI", [3] = "SPIN"}
function IEex_GetObjectSpellRES(share)
	local actionID = IEex_ReadWord(share + 0x476, 0x0)
	local spellRES = ""
	if actionID == 31 or actionID == 95 or actionID == 113 or actionID == 114 or actionID == 191 or actionID == 192 then
		spellRES = IEex_ReadString(IEex_ReadDword(share + 0x538))
		if spellRES == "" then
			local spellIDS = IEex_ReadWord(share + 0x52C, 0x0)
			if IEex_SpellIDSPrefix[math.floor(spellIDS / 1000)] ~= nil then
				spellRES = IEex_SpellIDSPrefix[math.floor(spellIDS / 1000)] .. (spellIDS % 1000)
			end
		end
	end
	return spellRES
end

function IEex_GetActorSpellRES(actorID)
	local share = IEex_GetActorShare(actorID)
	if not IEex_IsObjectSprite(share) then return "" end
	return IEex_GetObjectSpellRES(share)
end

-- Returns the resref of the item the actor has in the chosen inventory slot (from REALSLOT.IDS).
function IEex_GetItemSlotRES(actorID, slot)
	if not IEex_IsSprite(actorID, true) then return "" end
	local share = IEex_GetActorShare(actorID)
	local slotData = IEex_ReadDword(share + 0x4AD8 + slot * 0x4)
	if slotData <= 0 then return "" end
	return IEex_ReadLString(slotData + 0xC, 8)
end

-- Returns the slot number of the actor's currently equipped weapon (from REALSLOT.IDS).
-- If the actor has a launcher equipped, it returns the slot number of the ammo.
function IEex_GetEquippedWeaponSlot(actorID)
	if not IEex_IsSprite(actorID, true) then return 0 end
	local share = IEex_GetActorShare(actorID)
	return IEex_ReadByte(share + 0x4BA4, 0x0)
end

-- Returns the resref of the actor's currently equipped weapon.
-- If the actor has a launcher equipped, it returns the resref of the ammo.
function IEex_GetEquippedWeaponRES(actorID)
	if not IEex_IsSprite(actorID, true) then return "" end
	return IEex_GetItemSlotRES(actorID, IEex_GetEquippedWeaponSlot(actorID))
end

-- Returns the current header number of the actor's currently equipped weapon.
-- For example, if the actor is wielding a throwing axe, this will return 0 or 1 depending
-- on whether the axe is being used as ranged weapon or a melee weapon. In most other cases,
-- it will return 0.
function IEex_GetEquippedWeaponHeader(actorID)
	if not IEex_IsSprite(actorID, true) then return 0 end
	local share = IEex_GetActorShare(actorID)
	return IEex_ReadByte(share + 0x4BA6, 0x0)
end

-- Returns the resref of the actor's currently equipped launcher.
-- Returns "" if no launcher is equipped.
function IEex_GetLauncherRES(actorID, slot)
	if not IEex_IsSprite(actorID, true) then return "" end
	local launcherRES = ""
	IEex_IterateActorEffects(actorID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
		if theopcode == 288 and theparameter2 == 241 and thespecial == 7 then
			launcherRES = IEex_ReadLString(eData + 0x94, 8)
		end
	end)
	return launcherRES
end

-- Returns the actor's direction (from DIR.IDS).
function IEex_GetActorDirection(actorID)
	if not IEex_IsSprite(actorID, true) then return 0 end
	local share = IEex_GetActorShare(actorID)
	return IEex_ReadByte(share + 0x537E, 0x0)
end

-- Returns the actor's direction (from DIR.IDS).
function IEex_GetActorDirection(actorID)
	if not IEex_IsSprite(actorID, true) then return 0 end
	local share = IEex_GetActorShare(actorID)
	return IEex_ReadByte(share + 0x537E, 0x0)
end

key_angles = {-90, -67.5, -45, -22.5, 0, 22.5, 45, 67.5, 90}
function IEex_GetActorRequiredDirection(actorID, targetX, targetY)
	if not IEex_IsSprite(actorID, true) then return 0 end
	local share = IEex_GetActorShare(actorID)
	local sourceX, sourceY = IEex_GetActorLocation(actorID)
	local deltaX = targetX - sourceX
	local deltaY = targetY - sourceY
	local angle = 90
	if deltaX ~= 0 then
		angle = math.deg(math.atan(deltaY / deltaX))
		for i = 1, 9, 1 do
			if (angle >= key_angles[i] and angle - 11.25 <= key_angles[i]) or (angle <= key_angles[i] and angle + 11.25 >= key_angles[i]) then
				if deltaX < 0 then
					return (i - 1)
				elseif deltaX > 0 then
					return ((i + 7) % 16)
				end
			end
		end
	else
		if deltaY >= 0 then
			return 0
		else
			return 8
		end
	end
end

-- Sanity function to help work with number ranges that are cyclic, (like actor direction).
-- Example:
-- 	IEex_CyclicBound(num, 0, 15)
-- defines a range of 0 to 15. num = 16 rolls over to 0, as does num = 32. num = -1 wraps around to 15, as does num = -17.
function IEex_CyclicBound(num, lowerBound, upperBound)
	local tolerance = upperBound - lowerBound + 1
	local cycleCount = math.floor((num - lowerBound) / tolerance)
	return num - tolerance * cycleCount
end

-- Returns true if num2 is within <range> positions of num in the cyclic bounds. See IEex_CyclicBound() for more info about cyclic ranges.
function IEex_WithinCyclicRange(num, num2, range, lowerBound, higherBound)
	if num2 < (lowerBound + range) then
		-- Underflows
		return num > IEex_CyclicBound(num2 + higherBound - range + 1, lowerBound, higherBound) or num < (num2 + range)
	elseif num2 <= (higherBound - range + 1) then
		-- Normal
		return num > (num2 - range) and num < (num2 + range)
	else
		-- Overflows
		return num > (num2 - range) or num < IEex_CyclicBound(num2 + range, lowerBound, higherBound)
	end
end

function IEex_DirectionWithinCyclicRange(attackerID, targetID, range)
	local attackerDirection = IEex_GetActorDirection(attackerID)
	local targetDirection = IEex_GetActorDirection(targetID)
	return IEex_WithinCyclicRange(attackerDirection, targetDirection, range, 0, 15)
end

-- Returns true if the attackerID actor's direction is sufficent to backstab the targetID actor.
function IEex_IsValidBackstabDirection(attackerID, targetID)
	local attackerDirection = IEex_GetActorDirection(attackerID)
	local targetDirection = IEex_GetActorDirection(targetID)
	local targetX, targetY = IEex_GetActorLocation(targetID)
	local requiredDirection = IEex_GetActorRequiredDirection(attackerID, targetX, targetY)
	return (IEex_WithinCyclicRange(attackerDirection, targetDirection, 3, 0, 15) and IEex_WithinCyclicRange(attackerDirection, requiredDirection, 3, 0, 15))
end

function IEex_IterateActorEffects(actorID, func)

	if not IEex_IsSprite(actorID, true) then return end
	local sprite = IEex_GetActorShare(actorID)
	
	-- Equipped List
	local equippedList = sprite + 0x5526
	IEex_IterateCPtrListNode(equippedList, function(effect, node)
		func(effect - 0x4, equippedList, node)
	end)
	
	-- Timed List
	local timedList = sprite + 0x54FA
	IEex_IterateCPtrListNode(timedList, function(effect, node)
		func(effect - 0x4, timedList, node)
	end)
end

function IEex_IterateActorTimedEffects(actorID, func)
	if not IEex_IsSprite(actorID, true) then return end
	local esi = IEex_ReadDword(IEex_GetActorShare(actorID) + 0x552A)
	while esi ~= 0x0 do
		local edi = IEex_ReadDword(esi + 0x8) - 0x4
		if edi > 0x0 then
			func(edi)
		end
		esi = IEex_ReadDword(esi)
	end
end

function IEex_IterateActorEquippedEffects(actorID, func)
	if not IEex_IsSprite(actorID, true) then return end
	local esi = IEex_ReadDword(IEex_GetActorShare(actorID) + 0x54FE)
	while esi ~= 0x0 do
		local edi = IEex_ReadDword(esi + 0x8) - 0x4
		if edi > 0x0 then
			func(edi)
		end
		esi = IEex_ReadDword(esi)
	end
end

ex_kit_unusability_locations = {
[0x40] = {0x2F, 0x40},
[0x80] = {0x2F, 0x80},
[0x100] = {0x2D, 0x1},
[0x200] = {0x2D, 0x2},
[0x400] = {0x2D, 0x4},
[0x800] = {0x2D, 0x8},
[0x1000] = {0x2D, 0x10},
[0x2000] = {0x2D, 0x20},
}

function IEex_CanLearnScroll(actorID, itemData)
	if (bit.band(IEex_ReadDword(itemData + 0x1E), 0x400) > 0) or IEex_GetActorStat(actorID, 106) == 0 or IEex_ReadWord(itemdata + 0x1C, 0x0) ~= 11 or IEex_ReadWord(itemdata + 0x68, 0x0) < 2 then
		return false
	end
	local kitUnusability = ex_kit_unusability_locations[IEex_GetActorStat(actorID, 89)]
	if kitUnusability == nil then
		return true
	elseif bit.band(IEex_ReadByte(itemData + kitUnusability[1], 0x0), kitUnusability[2]) > 0 then
		return false
	end
	return true
end

function IEex_GetDistance(x1, y1, x2, y2)
	return math.floor((((x1 - x2) ^ 2) + ((y1 - y2) ^ 2)) ^ .5)
end

function IEex_GetDistanceIsometric(x1, y1, x2, y2)
	return math.floor(((x1 - x2) ^ 2 + (4/3 * (y1 - y2)) ^ 2) ^ .5)
end

ex_classid_listspll = {[2] = 1, [3] = 2, [4] = 3, [7] = 4, [8] = 5, [10] = 6, [11] = 7}
ex_kitid_listdomn = {[0x8000] = 1, [0x10000] = 2, [0x20000] = 3, [0x40000] = 4, [0x80000] = 5, [0x100000] = 6, [0x200000] = 7, [0x400000] = 8, [0x800000] = 9}
function IEex_GetClassSpellLevel(actorID, casterClass, spellRES)
	local classSpellLevel = 0
	if ex_classid_listspll[casterClass] ~= nil and ex_listspll[spellRES] ~= nil then
		classSpellLevel = ex_listspll[spellRES][ex_classid_listspll[casterClass]]
	end
	if classSpellLevel == 0 and casterClass == 3 then
		local casterKit = IEex_GetActorStat(actorID, 89)
		if ex_kitid_listdomn[casterKit] ~= nil and ex_listdomn[spellRES] ~= nil then
			classSpellLevel = ex_listdomn[spellRES][ex_kitid_listdomn[casterKit]]
		end
	end
	if ex_classid_listspll[casterClass] == nil and ex_listspll[spellRES] ~= nil then
		for k, v in ipairs(ex_listspll[spellRES]) do
			if v > 0 and (classSpellLevel == 0 or v < classSpellLevel) then
				classSpellLevel = v
			end
		end
	end
	return classSpellLevel
end

function IEex_CompareActorAllegiances(actorID1, actorID2)
	if not IEex_IsSprite(actorID1, true) or not IEex_IsSprite(actorID2, true) then return -1 end
	local creatureData1 = IEex_GetActorShare(actorID1)
	local creatureData2 = IEex_GetActorShare(actorID2)
	local ea1 = IEex_ReadByte(creatureData1 + 0x24, 0x0)
	local ea2 = IEex_ReadByte(creatureData2 + 0x24, 0x0)
	if ((ea1 >= 2 and ea1 <= 30) and (ea2 >= 200)) or ((ea1 >= 200) and (ea2 >= 2 and ea2 <= 30)) then
		return -1
	elseif ((ea1 >= 2 and ea1 <= 30) and (ea2 >= 2 and ea2 <= 30)) or ((ea1 >= 200) and (ea2 >= 200)) or creatureData1 == creatureData2 then
		return 1
	else
		return 0
	end
end

function IEex_IsActorDead(actorID)
	local share = IEex_GetActorShare(actorID)
	return bit.band(IEex_ReadDword(share + 0x5BC), 0xFC0) ~= 0x0
end

function IEex_IsObjectSprite(object, allowDead)
	return object ~= 0x0 -- share != NULL
	   and IEex_ReadByte(object + 0x4, 0) == 0x31 -- m_objectType == TYPE_SPRITE
	   and (allowDead or bit.band(IEex_ReadDword(object + 0x5BC), 0xFC0) == 0x0) -- allowDead or Status (not includes) STATE_*_DEATH
end

function IEex_IsSprite(actorID, allowDead)
	return IEex_IsObjectSprite(IEex_GetActorShare(actorID), allowDead)
end

function IEex_IsObjectAIBase(object)
	return object ~= 0x0 and IEex_IsBitSet(IEex_ReadByte(object + 0x4), 0)
end

function IEex_IsActorAIBase(actorID)
	return IEex_IsObjectAIBase(IEex_GetActorShare(actorID))
end

function IEex_GetSpriteBaseStats(sprite)
	return sprite + 0x5A4
end

function IEex_GetActorBaseStats(actorID)
	return IEex_GetSpriteBaseStats(IEex_GetActorShare(actorID))
end

function IEex_GetSpriteDerivedStats(sprite)
	return sprite + 0x920
end

function IEex_GetSpriteTempStats(sprite)
	return sprite + 0x1778
end

function IEex_GetActorDerivedStats(actorID)
	return IEex_GetSpriteDerivedStats(IEex_GetActorShare(actorID))
end

----------------
-- Game State --
----------------

function IEex_GetButtonArray()
	return IEex_GetGameData() + 0x1C78
end

function IEex_GetActionbarState()
	return IEex_ReadDword(IEex_GetButtonArray() + 0x1982)
end

function IEex_GetActionbarScrollIndex()
	return IEex_ReadDword(IEex_GetButtonArray() + 0x197A)
end

function IEex_GetActionbarButtonType(nIndex)
	if nIndex < 0 or nIndex > 11 then IEex_Error("Bad nIndex") end
	return IEex_ReadDword(IEex_GetButtonArray() + 0x16B0 + nIndex * 0x4)
end

function IEex_GetCurrentActionbarQuickButtons()
	return IEex_ReadDword(0x8E6820)
end

function IEex_SetActionbarState(nState, bUnknown)
	IEex_Call(0x589110, {bUnknown or 0, nState}, IEex_GetButtonArray(), 0x0)
end

function IEex_SetActionbarButton(actorID, customizableButtonIndex, buttonType)

	if not IEex_IsSprite(actorID, true) then return end
	local customizableActionbarSlotTypes = IEex_GetActorShare(actorID) + 0x3D14
	IEex_WriteDword(customizableActionbarSlotTypes + customizableButtonIndex * 0x4, buttonType)

	if IEex_GetActionbarState() == 0x72 and IEex_IsActorSolelySelected(actorID) then
		-- CInfGame_UpdateActionbar
		IEex_Call(0x5ADAE0, {}, IEex_GetGameData(), 0x0)
	end
end

function IEex_GetCVariable(CVariableHash, name)

	local manager = IEex_NewMemoryManager({
		{
			["name"] = "varChars",
			["struct"] = "string",
			["constructor"] = {
				["luaArgs"] = {name},
			},
		},
		{
			["name"] = "varString",
			["struct"] = "CString",
			["constructor"] = {
				["variant"] = "fromString",
				["args"] = {"varChars"},
			},
			["noDestruct"] = true,
		},
	})

	local varString = IEex_ReadDword(manager:getAddress("varString"))

	-- CVariableHash_FindKey
	local CVariable = IEex_Call(IEex_ReadDword(IEex_ReadDword(CVariableHash) + 0x4), {varString}, CVariableHash, 0x0)
	manager:free()
	return CVariable
end

function IEex_GetVariable(CVariableHash, name)
	local CVariable = IEex_GetCVariable(CVariableHash, name)
	if CVariable == 0x0 then return 0 end
	return IEex_ReadDword(CVariable + 0x28)
end

function IEex_SetVariable(CVariableHash, name, val)

	local CVariable = IEex_GetCVariable(CVariableHash, name)

	if CVariable == 0x0 then

		CVariable = IEex_Malloc(0x54)
		IEex_Call(0x452BD0, {}, CVariable, 0x0)
		IEex_WriteLString(CVariable, name:upper(), 32)
		IEex_WriteDword(CVariable + 0x28, val)

		-- CVariableHash_AddKey
		IEex_Call(IEex_ReadDword(IEex_ReadDword(CVariableHash)), {CVariable}, CVariableHash, 0x0)
		IEex_Free(CVariable)
	else
		IEex_WriteDword(CVariable + 0x28, val)
	end
end

function IEex_GetGlobal(name)
	return IEex_GetVariable(IEex_GetGameData() + 0x47FC, name)
end

function IEex_SetGlobal(name, val)
	IEex_SetVariable(IEex_GetGameData() + 0x47FC, name, val)
end

function IEex_GetActorLocal(actorID, name)

	local sprite = IEex_GetActorShare(actorID)
	if not IEex_IsObjectSprite(sprite, true) then return 0 end
	-- Force the creature's effects list to be evaluated if it hasn't already.
	-- Since locals are stored as effects on the creature the engine won't report them
	-- until the creature has been processed at least once.
	IEex_EnsureSpriteEffectListProcessed(sprite)
	return IEex_GetVariable(IEex_ReadDword(sprite + 0x72B2), name)
end

function IEex_SetActorLocal(actorID, name, val)
	if not IEex_IsSprite(actorID, true) then return end
	IEex_SetVariable(IEex_ReadDword(IEex_GetActorShare(actorID) + 0x72B2), name, val)
end

function IEex_Eval(actionString, portraitIndex)

	local manager = IEex_NewMemoryManager({
		{
			["name"] = "scriptFile",
			["struct"] = "CAIScriptFile",
		},
		{
			["name"] = "actionStringChars",
			["struct"] = "string",
			["constructor"] = {
				["luaArgs"] = {actionString},
			},
		},
		{
			["name"] = "actionCString",
			["struct"] = "CString",
			["constructor"] = {
				["variant"] = "fromString",
				["args"] = {"actionStringChars"},
			},
			["noDestruct"] = true,
		},
	})

	local CAIScriptFile = manager:getAddress("scriptFile")
	local actionCString = manager:getAddress("actionCString")

	-- CAIScriptFile_ParseResponseString
	IEex_Call(0x410120, {IEex_ReadDword(actionCString)}, CAIScriptFile, 0x0)

	-- m_errors
	local errors = IEex_ReadString(IEex_ReadDword(CAIScriptFile + 0x16))
	if errors == "" then

		local actorID = -1
		if portraitIndex then
			if portraitIndex >= 0 and portraitIndex <= 5 then
				actorID = IEex_GetActorIDPortrait(portraitIndex)
			else
				actorID = portraitIndex
			end
		else
			actorID = IEex_GetActorIDCursor()
		end

		if actorID == -1 then
			-- pGame->m_gameAreas[pGame->m_visibleArea]->m_nAIIndex
			local m_pObjectGame = IEex_GetGameData()
			local m_visibleArea = IEex_ReadByte(m_pObjectGame + 0x37E0, 0)
			local CGameArea = IEex_ReadDword(m_pObjectGame + m_visibleArea * 0x4 + 0x37E2)
			actorID = IEex_ReadDword(CGameArea + 0x41A)
		end

		local share = IEex_GetActorShare(actorID)
		if share <= 0 then
			IEex_DisplayString("Action Errors:: " .. "The creature to do the action does not exist.")
			manager:free()
			return
		end
		local CGameAIBase_InsertAction = IEex_ReadDword(IEex_ReadDword(share) + 0x88)

		local m_actionList = IEex_ReadDword(CAIScriptFile + 0x12) + 0x8
		IEex_IterateCPtrList(m_actionList, function(CAIAction)
			IEex_Call(CGameAIBase_InsertAction, {CAIAction}, share, 0x0)
		end)
	else
		IEex_DisplayString("Action Errors:: "..errors)
	end

	manager:free()

end

function IEex_CreateCreature(resref)
	local mem = IEex_Malloc(0xC)
	IEex_WriteLString(mem, resref, 8)
	local resrefCStringPtr = mem + 0x8
	-- CResRef_GetResRefStr
	IEex_Call(0x78AA30, {resrefCStringPtr}, mem, 0x0)
	-- This is usually used with hardcoded resrefs by CtrlAltDelete:JeffKAttacks() and JeffKDefends()
	IEex_Call(0x4EC390, {IEex_ReadDword(resrefCStringPtr)}, nil, 0x0)
	IEex_Free(mem)
end

function IEex_CreateStatic(CGameArea, args)
	local CGameStatic
	IEex_RunWithStack(0x4C, function(esp)
		IEex_WriteArgs(esp, args, {
			{ "name",            0x0,  IEex_WriteType.LSTRING, 32, IEex_WriteFailType.ERROR               },
			{ "locX",            0x20, IEex_WriteType.WORD,        IEex_WriteFailType.DEFAULT, 0          },
			{ "locY",            0x22, IEex_WriteType.WORD,        IEex_WriteFailType.DEFAULT, 0          },
			{ "activeAtFlags",   0x24, IEex_WriteType.DWORD,       IEex_WriteFailType.DEFAULT, 0xFFFFFFFF },
			{ "animationResRef", 0x28, IEex_WriteType.RESREF,      IEex_WriteFailType.ERROR               },
			{ "animationNum",    0x30, IEex_WriteType.WORD,        IEex_WriteFailType.DEFAULT, 0          },
			{ "frameNum",        0x32, IEex_WriteType.WORD,        IEex_WriteFailType.DEFAULT, 0          },
			{ "appearanceFlags", 0x34, IEex_WriteType.DWORD,       IEex_WriteFailType.DEFAULT, 0          },
			{ "locZ",            0x38, IEex_WriteType.WORD,        IEex_WriteFailType.DEFAULT, 0          },
			{ "translucency",    0x3A, IEex_WriteType.WORD,        IEex_WriteFailType.DEFAULT, 0          },
			{ "startRange",      0x3C, IEex_WriteType.WORD,        IEex_WriteFailType.DEFAULT, 0          },
			{ "loopProb",        0x3E, IEex_WriteType.BYTE,        IEex_WriteFailType.DEFAULT, 0          },
			{ "startDelay",      0x3F, IEex_WriteType.BYTE,        IEex_WriteFailType.DEFAULT, 0          },
			{ "paletteResRef",   0x40, IEex_WriteType.RESREF,      IEex_WriteFailType.DEFAULT, ""         },
			{ "unknown",         0x48, IEex_WriteType.DWORD,       IEex_WriteFailType.DEFAULT, 0          },
		})
		CGameStatic = IEex_Malloc(0x194)
		-- CGameStatic_Construct()
		IEex_Call(0x4CA530, {esp, CGameArea}, CGameStatic, 0x0)
	end)
	return CGameStatic
end

function IEex_MoveStatic(CGameStatic, x, y)
	y = y + IEex_ReadWord(CGameStatic + 0xA6, 0)
	IEex_WriteDword(CGameStatic + 0x6, x)
	IEex_WriteDword(CGameStatic + 0xA, y)
	IEex_WriteWord(CGameStatic + 0x8E, x)
	IEex_WriteWord(CGameStatic + 0x90, y)
end

function IEex_GetCInfinityFromArea(CGameArea)
	return CGameArea + 0x4CC
end

function IEex_GetCInfinity()
	local m_pObjectGame = IEex_GetGameData()
	local m_visibleArea = IEex_ReadByte(m_pObjectGame + 0x37E0, 0)
	local CGameArea = IEex_ReadDword(m_pObjectGame + m_visibleArea * 0x4 + 0x37E2)
	return IEex_GetCInfinityFromArea(CGameArea)
end

function IEex_GetGameData()
	local g_pBaldurChitin = IEex_ReadDword(0x8CF6DC)
	local m_pObjectGame = IEex_ReadDword(g_pBaldurChitin + 0x1C54)
	return m_pObjectGame
end

function IEex_GetEngineCharacter()
	local g_pBaldurChitin = IEex_ReadDword(0x8CF6DC)
	return IEex_ReadDword(g_pBaldurChitin + 0x1C60)
end

function IEex_GetEngineCharacterPanelID()
	local characterScreen = IEex_GetEngineCharacter()
	local pTail = IEex_ReadDword(characterScreen + 0x632) -- m_lPopupStack.m_pNodeTail
	local panelID = pTail ~= 0x0 and IEex_ReadDword(IEex_ReadDword(pTail + 0x8) + 0x20) or -1
	return panelID
end

function IEex_EngineCharacterUpdatePopupPanel()
	local characterScreen = IEex_GetEngineCharacter()
	local pTail = IEex_ReadDword(characterScreen + 0x632) -- m_lPopupStack.m_pNodeTail
	local panelID = pTail ~= 0x0 and IEex_ReadDword(IEex_ReadDword(pTail + 0x8) + 0x20) or -1
	if panelID == -1 then return end
	local share = IEex_GetActorShare(IEex_ReadDword(characterScreen + 0x136))
	-- CScreenCharacter_UpdatePopupPanel()
	IEex_Call(0x5E0B20, {share, panelID}, characterScreen, 0x0)
end

function IEex_GetEngineCreateChar()
	local g_pBaldurChitin = IEex_ReadDword(0x8CF6DC)
	return IEex_ReadDword(g_pBaldurChitin + 0x1C64)
end

function IEex_EngineCreateCharUpdatePopupPanel()
	local createCharScreen = IEex_GetEngineCreateChar()
	local pTail = IEex_ReadDword(createCharScreen + 0x53E) -- m_lPopupStack.m_pNodeTail
	local panelID = pTail ~= 0x0 and IEex_ReadDword(IEex_ReadDword(pTail + 0x8) + 0x20) or -1
	if panelID == -1 then return end
	local share = IEex_GetActorShare(IEex_ReadDword(createCharScreen + 0x4E2))
	-- CScreenCreateChar_UpdatePopupPanel()
	IEex_Call(0x60CEB0, {share, panelID}, createCharScreen, 0x0)
end

function IEex_GetEngineCreateCharPanelID()
	local createCharScreen = IEex_GetEngineCreateChar()
	local pTail = IEex_ReadDword(createCharScreen + 0x53E) -- m_lPopupStack.m_pNodeTail
	local panelID = pTail ~= 0x0 and IEex_ReadDword(IEex_ReadDword(pTail + 0x8) + 0x20) or -1
	return panelID
end

function IEex_GetVisibleArea()
	local m_pObjectGame = IEex_GetGameData()
	local m_visibleArea = IEex_ReadByte(m_pObjectGame + 0x37E0, 0)
	return IEex_ReadDword(m_pObjectGame + m_visibleArea * 0x4 + 0x37E2)
end

function IEex_GetGameTick()
	return IEex_ReadDword(IEex_GetGameData() + 0x1B78)
end

function IEex_IsNight()
	local hour = math.floor((IEex_GetGameTick() % 108000) / 4500)
	return (hour < 7 or hour >= 22)
end

-- Returns a number between 1 (Very Easy) and 6 (Heart of Fury Mode)
function IEex_GetGameDifficulty()
	local gameData = IEex_GetGameData()
	if bit.band(IEex_ReadByte(gameData + 0x44AC, 0x0), 0x1) > 0 then
		return 6
	else
		return IEex_ReadByte(gameData + 0x4456, 0x0)
	end
end

function IEex_GetActiveEngine()
	local g_pBaldurChitin = IEex_ReadDword(0x8CF6DC)
	return IEex_ReadDword(g_pBaldurChitin + 0x3C4)
end

function IEex_GetEngineSpell()
	local g_pBaldurChitin = IEex_ReadDword(0x8CF6DC)
	return IEex_ReadDword(g_pBaldurChitin + 0x1C80)
end

function IEex_IsGamePaused()
	return (bit.band(IEex_ReadByte(IEex_GetGameData() + 0x48E4, 0x0), 0x1) > 0)
end

function IEex_InCutsceneMode()
	local m_gameSave = IEex_GetGameData() + 0x422C
	return IEex_ReadDword(m_gameSave + 0x1B6) == 0x142
end

function IEex_IsDialogWindowOpen()
	local worldScreen = IEex_GetEngineWorld()
	return IEex_GetActiveEngine() == worldScreen and IEex_IsPanelActive(IEex_GetPanelFromEngine(worldScreen, 7))
end

function IEex_AddPartyXP(nAmount, bNotQuestXP, bAmountIsChallengeRating)
	IEex_Call(0x5C0BB0, {bAmountIsChallengeRating and 1 or 0, bNotQuestXP and 1 or 0, nAmount}, IEex_GetGameData(), 0x0)
end

function IEex_DisplayString(string)

	string = tostring(string)
	local stringMem = IEex_Malloc(#string + 1)
	IEex_WriteString(stringMem, string)

	local CString = IEex_Malloc(0x4)
	IEex_Call(0x7FCC88, {stringMem}, CString, 0x0)
	IEex_Free(stringMem)

	IEex_Call(0x4EC1C0, {IEex_ReadDword(CString)}, nil, 0x0)
	IEex_Free(CString)

end

-- Like IEex_DisplayString, but can print nil values, booleans, and entire tables.
function IEex_DS(string)
	IEex_DisplayString(IEex_ToString(string))
end

function IEex_ToString(string)
	if string == nil then
		return "nil"
	else
		local stringType = type(string)
		if stringType == "boolean" then
			if string then
				return "true"
			else
				return "false"
			end
		elseif stringType == "function" then
			return "function()"
		elseif stringType == "table" then
			local tableString = "{"
			if string[1] == nil then
				for k, v in pairs(string) do
					tableString = tableString .. "[" .. IEex_ToString(k) .. "] = " .. IEex_ToString(v) .. ", "
				end
			else
				for k, v in ipairs(string) do
					tableString = tableString .. IEex_ToString(v) .. ", "
				end
			end
			tableString = tableString .. "}"
			return tableString
		elseif stringType == "string" then
			return "\"" .. string .. "\""
		else
			return string
		end

	end
end

function IEex_TF(bool)
	if bool == true then
		IEex_DisplayString("True")
	elseif bool == false then
		IEex_DisplayString("False")
	else
		IEex_DisplayString("Huh?")
	end
end

function IEex_SetToken(tokenString, valueString)

	valueString = tostring(valueString)
	local tokenStringLen = #tokenString
	local mem = IEex_Malloc(tokenStringLen + #valueString + 2)

	local valueStringMem = mem + tokenStringLen + 0x1
	IEex_WriteString(mem, tokenString)
	IEex_WriteString(valueStringMem, valueString)

	local g_pBaldurChitin = IEex_ReadDword(0x8CF6DC)
	-- GetTokenCString
	local CString = IEex_Call(0x7FC1A5, {mem}, g_pBaldurChitin + 0x1CC8, 0x0)

	-- CString_equ_raw_string
	IEex_Call(0x7FCD57, {valueStringMem}, CString, 0x0)
	IEex_Free(mem)
end

function IEex_2DALoad(resref)

	local C2DArray = IEex_Malloc(0x24)
	IEex_WriteDword(C2DArray + 0x0, 0x0) -- lock?
	IEex_WriteDword(C2DArray + 0x4, 0x0) -- res
	IEex_WriteLString(C2DArray + 0x8, "", 0x8) -- resref
	IEex_WriteDword(C2DArray + 0x10, 0x0) -- m_pNamesX
	IEex_WriteDword(C2DArray + 0x14, 0x0) -- m_pNamesY
	IEex_WriteDword(C2DArray + 0x18, 0x0) -- m_pArray
	IEex_WriteDword(C2DArray + 0x1C, IEex_ReadDword(0x8C1758)) -- defaultCString (afxPchNil)
	IEex_WriteWord(C2DArray + 0x20, 0x0) -- m_nSizeX
	IEex_WriteWord(C2DArray + 0x22, 0x0) -- m_nSizeY

	local resrefMem = IEex_Malloc(0x8)
	IEex_WriteLString(resrefMem, resref, 0x8)
	IEex_Call(0x402B70, {resrefMem}, C2DArray, 0x0)
	IEex_Free(resrefMem)

	return C2DArray
end

function IEex_2DADemand(arrayName)
	local C2DArray = IEex_Loaded2DAs[arrayName]
	if not C2DArray then
		C2DArray = IEex_2DALoad(arrayName)
		if IEex_ReadDword(C2DArray + 0x18) == 0x0 then
			IEex_Free(C2DArray)
			IEex_TracebackMessage("IEex CRITICAL ERROR - Couldn't find " .. arrayName .. ".2DA!")
			return nil
		end
		IEex_Loaded2DAs[arrayName] = C2DArray
	end
	return C2DArray
end

function IEex_2DAFindColumn(C2DArray, columnString)
	local m_nSizeX = IEex_ReadWord(C2DArray + 0x20, 0)
	local columnIndex = nil
	local columnAccess = IEex_ReadDword(C2DArray + 0x10)
	for i = 1, m_nSizeX, 1 do
		local column = IEex_ReadString(IEex_ReadDword(columnAccess))
		if column == columnString then
			columnIndex = i - 1 -- zero-indexing in memory
			break
		end
		columnAccess = columnAccess + 0x4
	end
	return columnIndex
end

function IEex_2DAFindRow(C2DArray, rowString)
	local m_nSizeY = IEex_ReadWord(C2DArray + 0x20, 1)
	local rowIndex = nil
	local rowAccess = IEex_ReadDword(C2DArray + 0x14)
	for i = 1, m_nSizeY, 1 do
		local row = IEex_ReadString(IEex_ReadDword(rowAccess))
		if row == rowString then
			rowIndex = i - 1 -- zero-indexing in memory
			break
		end
		rowAccess = rowAccess + 0x4
	end
	return rowIndex
end

function IEex_2DAGetAt(C2DArray, x, y)
	local array = IEex_ReadDword(C2DArray + 0x18)
	local m_nSizeX = IEex_ReadWord(C2DArray + 0x20, 0)
	local accessOffset = (m_nSizeX * y + x) * 4
	return IEex_ReadString(IEex_ReadDword(array + accessOffset))
end

function IEex_2DAGetAtStrings(arrayName, columnString, rowString)

	local C2DArray = IEex_2DADemand(arrayName)
	local defaultString = IEex_ReadString(IEex_ReadDword(C2DArray + 0x1C))

	local columnIndex = IEex_2DAFindColumn(C2DArray, columnString)
	-- Tried to lookup a non-existent column, serve default
	if not columnIndex then return defaultString end

	local rowIndex = IEex_2DAFindRow(C2DArray, rowString)
	-- Tried to lookup a non-existent row, serve default
	if not rowIndex then return defaultString end

	local array = IEex_ReadDword(C2DArray + 0x18)
	local m_nSizeX = IEex_ReadWord(C2DArray + 0x20, 0)
	local accessOffset = (m_nSizeX * rowIndex + columnIndex) * 4
	return IEex_ReadString(IEex_ReadDword(array + accessOffset))
end

function IEex_2DAGetAtRelated(arrayName, relatedColumn, columnString, compareFunc)

	local C2DArray = IEex_2DADemand(arrayName)
	local defaultString = IEex_ReadString(IEex_ReadDword(C2DArray + 0x1C))

	local relatedColumnIndex = IEex_2DAFindColumn(C2DArray, relatedColumn)
	if not relatedColumnIndex then return defaultString end

	local columnIndex = IEex_2DAFindColumn(C2DArray, columnString)
	if not columnIndex then return defaultString end

	local foundRowIndex = nil
	local maxRowIndex = IEex_ReadWord(C2DArray + 0x20, 1) - 1
	for rowIndex = 0, maxRowIndex, 1 do
		if compareFunc(IEex_2DAGetAt(C2DArray, relatedColumnIndex, rowIndex)) then
			foundRowIndex = rowIndex
			break
		end
	end

	if not foundRowIndex then return defaultString end

	return IEex_2DAGetAt(C2DArray, columnIndex, foundRowIndex)
end

----------------------
-- ActorID Fetching --
----------------------

function IEex_GetActorIDShare(share)
	if share <= 65535 or share == nil then return 0 end
	return IEex_ReadDword(share + 0x5C)
end

function IEex_GetActorIDCursor()

	local g_pBaldurChitin = IEex_ReadDword(0x8CF6DC)
	local m_pObjectGame = IEex_ReadDword(g_pBaldurChitin + 0x1C54)

	local m_visibleArea = IEex_ReadByte(m_pObjectGame + 0x37E0, 0)
	-- m_gameAreas[m_visibleArea]
	local CGameArea = IEex_ReadDword(m_pObjectGame + m_visibleArea * 0x4 + 0x37E2)
	local m_iPicked = -1
	if CGameArea > 0 then
		m_iPicked = IEex_ReadDword(CGameArea + 0x246)
	end

	return m_iPicked
end

function IEex_GetActorIDCharacter(characterNum)
	if characterNum >= 0 and characterNum <= 5 then
		return IEex_ReadDword(IEex_GetGameData() + 0x3816 + characterNum * 0x4)
	end
	return -1
end

function IEex_GetActorIDPortrait(portraitNum)
	if portraitNum >= 0 and portraitNum <= 5 then
		return IEex_ReadDword(IEex_GetGameData() + 0x382E + portraitNum * 0x4)
	end
	return -1
end

function IEex_GetActorSummonerID(actorID)
	local share = IEex_GetActorShare(actorID)
--	if share <= 0 then return -1 end
	if not IEex_IsSprite(actorID, true) then return -1 end
	local summonerID = IEex_Helper_GetBridge("IEex_ConstantID", IEex_ReadDword(share + 0x72C))
	if not IEex_IsSprite(summonerID, true) then
		return -1
	else
		return summonerID
	end
end

function IEex_GetActorPortraitNum(actorID)
	local curAddress = IEex_GetGameData() + 0x382E
	for i = 0, 5 do
		if IEex_ReadDword(curAddress) == actorID then return i end
		curAddress = curAddress + 0x4
	end
	return -1
end

function IEex_IsPartyMember(actorID)
	return (IEex_GetActorPortraitNum(actorID) ~= -1)
end

function IEex_GetActorIDSelected()
	local nodeHead = IEex_ReadDword(IEex_GetGameData() + 0x388E)
	if nodeHead ~= 0x0 then
		return IEex_ReadDword(nodeHead + 0x8)
	end
	return -1
end

function IEex_GetAllActorIDSelected()
	local ids = {}
	local CPtrList = IEex_GetGameData() + 0x388A
	IEex_IterateCPtrList(CPtrList, function(actorID)
		table.insert(ids, actorID)
	end)
	return ids
end

function IEex_IterateIDs(m_gameArea, requiredObjectType, func)
	if m_gameArea <= 0x0 then return end
	local areaList = IEex_ReadDword(m_gameArea + 0x996)
	while areaList ~= 0x0 do
		local areaListID = IEex_ReadDword(areaList + 0x8)
		local share = IEex_GetActorShare(areaListID)
		if share > 0 then
			local objectType = IEex_ReadByte(share + 0x4, 0)
			if objectType == requiredObjectType or requiredObjectType == -1 then
				func(areaListID)
			end
		end
		areaList = IEex_ReadDword(areaList)
	end
	local areaList = IEex_ReadDword(m_gameArea + 0x9B2)
	while areaList ~= 0x0 do
		local areaListID = IEex_ReadDword(areaList + 0x8)
		local share = IEex_GetActorShare(areaListID)
		if share > 0 then
			local objectType = IEex_ReadByte(share + 0x4, 0)
			if objectType == requiredObjectType or requiredObjectType == -1 then
				func(areaListID)
			end
		end
		areaList = IEex_ReadDword(areaList)
	end
end

function IEex_GetIDArea(actorID, requiredObjectType)
	local ids = {}
	local actorShare = IEex_GetActorShare(actorID)
	if actorShare <= 0 then return ids end
	local m_pArea = IEex_ReadDword(actorShare + 0x12)
	IEex_IterateIDs(m_pArea, requiredObjectType, function(areaActorID)
		table.insert(ids, areaActorID)
	end)
	return ids
end

function IEex_IterateContainers(actorID, func)
	IEex_IterateIDs(IEex_ReadDword(IEex_GetActorShare(actorID) + 0x12), 0x11, function(areaListID)
		local share = IEex_GetActorShare(areaListID)
		func(share)
	end)
end

function IEex_IterateDoors(actorID, func)
	IEex_IterateIDs(IEex_ReadDword(IEex_GetActorShare(actorID) + 0x12), 0x21, function(areaListID)
		local share = IEex_GetActorShare(areaListID)
		func(share)
	end)
end

function IEex_IterateTriggers(actorID, func)
	IEex_IterateIDs(IEex_ReadDword(IEex_GetActorShare(actorID) + 0x12), 0x41, function(areaListID)
		local share = IEex_GetActorShare(areaListID)
		func(share)
	end)
end

function IEex_IterateProjectiles(actorID, projectileID, func)
	IEex_IterateIDs(IEex_ReadDword(IEex_GetActorShare(actorID) + 0x12), 0, function(areaListID)
		local share = IEex_GetActorShare(areaListID)
		local vfptr = IEex_ReadDword(share)
		if (projectileID == -1 or IEex_ReadWord(share + 0x6E, 0x0) == projectileID) and vfptr ~= 8712412 and vfptr ~= 8712524 and vfptr ~= 8765200 and vfptr ~= 8765308 and vfptr ~= 8765416 and vfptr ~= 8705572 then
			func(share)
		end
	end)
end

function IEex_IterateFireballs(actorID, func)
	IEex_IterateIDs(IEex_ReadDword(IEex_GetActorShare(actorID) + 0x12), 0, function(areaListID)
		local share = IEex_GetActorShare(areaListID)
		local vfptr = IEex_ReadDword(share)
		if vfptr == 8712412 or vfptr == 8765416 then
			func(share)
		end
	end)
end

function IEex_IterateTemporals(actorID, func)
	IEex_IterateIDs(IEex_ReadDword(IEex_GetActorShare(actorID) + 0x12), 0, function(areaListID)
		local share = IEex_GetActorShare(areaListID)
		if IEex_ReadDword(share) == 8712524 then
			func(share)
		end
	end)
end

function IEex_IterateCastingGlows(actorID, func)
	IEex_IterateIDs(IEex_ReadDword(IEex_GetActorShare(actorID) + 0x12), 0, function(areaListID)
		local share = IEex_GetActorShare(areaListID)
		if IEex_ReadDword(share) == 8720284 then
			func(share)
		end
	end)
end

function IEex_GetOngoingProjectile(index)
	local ids = IEex_GetIDArea(IEex_GetActorIDPortrait(0), 0)
	if index <= #ids then
		return IEex_GetActorShare(ids[index])
	else
		return 0
	end
end

function IEex_GetActorShare(actorID)
	if not actorID then return 0 end
	local CGameObjectArray = IEex_GetGameData() + 0x372C

	local resultPtr = IEex_Malloc(0x4)
	IEex_Call(0x599A50, {-1, resultPtr, 0, actorID}, CGameObjectArray, 0x0)

	local toReturn = IEex_ReadDword(resultPtr)
	IEex_Free(resultPtr)
	return toReturn
end

function IEex_UndoActorShare(actorID)
	local CGameObjectArray = IEex_GetGameData() + 0x372C
	IEex_Call(0x599E70, {-1, 0, actorID}, CGameObjectArray, 0x0)
end

function IEex_GS(actorID)
	return IEex_GetActorShare(actorID)
end

function IEex_GIDC()
	return IEex_GetActorIDCursor()
end

function IEex_GIDS()
	return IEex_GetActorIDSelected()
end

function IEex_GIDA(requiredObjectType)
	return IEex_GetIDArea(IEex_GetActorIDCharacter(0), requiredObjectType)
end

function IEex_GSC()
	return IEex_GetActorShare(IEex_GetActorIDCursor())
end

function IEex_GSS()
	return IEex_GetActorShare(IEex_GetActorIDSelected())
end

function IEex_IIDS(requiredObjectType, func)
	IEex_IterateIDs(IEex_ReadDword(IEex_GetActorShare(IEex_GetActorIDCharacter(0)) + 0x12), requiredObjectType, func)
end

---------------------------------------------------------------------------
-- Functions which are called to determine if certain feats can be taken --
---------------------------------------------------------------------------

function Feats_True(actorID, featID)
	return true
end

function Feats_Assassin(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x626, 0x0) < 2 and IEex_ReadByte(creatureData + 0x62F, 0x0) > 0 and IEex_ReadByte(creatureData + 0x7B4, 0x0) >= 4 and IEex_ReadByte(creatureData + 0x7BA, 0x0) >= 4 and IEex_ReadByte(creatureData + 0x7BD, 0x0) >= 4 and bit.band(IEex_ReadByte(creatureData + 0x35, 0x0), 0x3) == 0x3)
end

function Feats_AugmentSummoning(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x785, 0x0) > 0)
end

function Feats_BlindingSpeed(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_GetActorBaseStat(actorID, 40) >= 23)
end
--[[
function Feats_CombatCasting(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local combatCastingFeatCount = 0
	local feats = IEex_Helper_GetBridgeNL("IEex_DerivedStatsData", IEex_GetSpriteDerivedStats(creatureData), "feats")
	local featIndex = IEex_Helper_GetBridgeNL(feats, "feat_index_"..featID)
	if featIndex then
		combatCastingFeatCount = IEex_Helper_GetBridgeNL(feats, featIndex, "count")
		if not combatCastingFeatCount then
			combatCastingFeatCount = 0
		end
	end
	if combatCastingFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x7B7, 0x0) >= 15)
	else
		return true
	end
end

function Prereq_CombatCasting(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local combatCastingFeatCount = 0
	local feats = IEex_Helper_GetBridgeNL("IEex_DerivedStatsData", IEex_GetSpriteDerivedStats(creatureData), "feats")
	local featIndex = IEex_Helper_GetBridgeNL(feats, "feat_index_"..featID)
	if featIndex then
		combatCastingFeatCount = IEex_Helper_GetBridgeNL(feats, featIndex, "count")
		if not combatCastingFeatCount then
			combatCastingFeatCount = 0
		end
	end
	if combatCastingFeatCount == 2 then
		return (IEex_ReadByte(creatureData + 0x7B7, 0x0) >= 15)
	else
		return true
	end
end
--]]

function Feats_CombatCasting(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	if ex_feat_id_offset[featID] == nil then return true end
	local combatCastingFeatCount = IEex_ReadSignedByte(creatureData + ex_feat_id_offset[featID], 0x0)
	if combatCastingFeatCount == -1 then
		local hasFeat = (bit.band(IEex_ReadDword(creatureData + 0x75C), 0x200) > 0)
		if hasFeat then
			combatCastingFeatCount = 1
		else
			combatCastingFeatCount = 0
		end
		IEex_WriteByte(creatureData + ex_feat_id_offset[featID], combatCastingFeatCount)
	end
	if combatCastingFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x7B7, 0x0) >= 15)
	else
		return true
	end
end

function Prereq_CombatCasting(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	if ex_feat_id_offset[featID] == nil then return true end
	local combatCastingFeatCount = IEex_ReadSignedByte(creatureData + ex_feat_id_offset[featID], 0x0)
	if combatCastingFeatCount == -1 then
		local hasFeat = (bit.band(IEex_ReadDword(creatureData + 0x75C), 0x200) > 0)
		if hasFeat then
			combatCastingFeatCount = 1
		else
			combatCastingFeatCount = 0
		end
		IEex_WriteByte(creatureData + ex_feat_id_offset[featID], combatCastingFeatCount)
	end
	if combatCastingFeatCount == 2 then
		return (IEex_ReadByte(creatureData + 0x7B7, 0x0) >= 15)
	else
		return true
	end
end

function Feats_CombatReflexes(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 1)
end

function Feats_ConcoctPotions(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x7B4, 0x0) >= 10)
end

function Feats_Counterspell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x628, 0x0) > 3 or IEex_ReadByte(creatureData + 0x629, 0x0) > 2 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 2 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 4 or IEex_ReadByte(creatureData + 0x630, 0x0) > 3 or IEex_ReadByte(creatureData + 0x631, 0x0) > 2)
end

function Feats_DamageReduction(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local damageReductionFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_DAMAGE_REDUCTION"], 0x0)
	if damageReductionFeatCount == 0 then
		return (IEex_GetActorBaseStat(actorID, 41) >= 21)
	elseif damageReductionFeatCount == 1 then
		return (IEex_GetActorBaseStat(actorID, 41) >= 23)
	elseif damageReductionFeatCount == 2 then
		return (IEex_GetActorBaseStat(actorID, 41) >= 25)
	else
		return true
	end
end

function Prereq_DamageReduction(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local damageReductionFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_DAMAGE_REDUCTION"], 0x0)
	if damageReductionFeatCount == 1 then
		return (IEex_GetActorBaseStat(actorID, 41) >= 21)
	elseif damageReductionFeatCount == 2 then
		return (IEex_GetActorBaseStat(actorID, 41) >= 23)
	elseif damageReductionFeatCount == 3 then
		return (IEex_GetActorBaseStat(actorID, 41) >= 25)
	else
		return true
	end
end

function Feats_DefensiveRoll(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x62F, 0x0) > 9)
end

function Feats_DefensiveStance(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 2)
--	return (IEex_ReadByte(creatureData + 0x627, 0x0) > 0 or IEex_ReadByte(creatureData + 0x62B, 0x0) > 0 or IEex_ReadByte(creatureData + 0x62C, 0x0) > 0 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 0 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 0)
end

function Feats_Dodge(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	if ex_feat_id_offset[featID] == nil then return true end
	local hasImprovedEvasion = (bit.band(IEex_ReadDword(creatureData + 0x75C), 0x80000000) ~= 0)
	local defensiveRollFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_DEFENSIVE_ROLL"], 0x0)
	local dodgeFeatCount = IEex_ReadSignedByte(creatureData + ex_feat_id_offset[featID], 0x0)
	if dodgeFeatCount == -1 then
		local hasFeat = (bit.band(IEex_ReadDword(creatureData + 0x75C), 0x10000) > 0)
		if hasFeat then
			dodgeFeatCount = 1
		else
			dodgeFeatCount = 0
		end
		IEex_WriteByte(creatureData + ex_feat_id_offset[featID], dodgeFeatCount)
	end
	if dodgeFeatCount == 0 then
		return (IEex_GetActorBaseStat(actorID, 40) >= 13)
	elseif dodgeFeatCount == 1 then
		return (IEex_GetActorBaseStat(actorID, 40) >= 25 and hasImprovedEvasion and defensiveRollFeatCount > 0)
	else
		return true
	end
end

function Prereq_Dodge(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	if ex_feat_id_offset[featID] == nil then return true end
	local hasImprovedEvasion = (bit.band(IEex_ReadDword(creatureData + 0x75C), 0x80000000) ~= 0)
	local defensiveRollFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_DEFENSIVE_ROLL"], 0x0)
	local dodgeFeatCount = IEex_ReadSignedByte(creatureData + ex_feat_id_offset[featID], 0x0)
	if dodgeFeatCount == -1 then
		local hasFeat = (bit.band(IEex_ReadDword(creatureData + 0x75C), 0x10000) > 0)
		if hasFeat then
			dodgeFeatCount = 1
		else
			dodgeFeatCount = 0
		end
		IEex_WriteByte(creatureData + ex_feat_id_offset[featID], dodgeFeatCount)
	end
	if dodgeFeatCount == 1 then
		return (IEex_GetActorBaseStat(actorID, 40) >= 13)
	elseif dodgeFeatCount == 2 then
		return (IEex_GetActorBaseStat(actorID, 40) >= 25 and hasImprovedEvasion and defensiveRollFeatCount > 0)
	else
		return true
	end
end

function Feats_EmpowerSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x628, 0x0) > 6 or IEex_ReadByte(creatureData + 0x629, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 7 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 7 or IEex_ReadByte(creatureData + 0x630, 0x0) > 5 or IEex_ReadByte(creatureData + 0x631, 0x0) > 4)
end

function Feats_ExtendSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x628, 0x0) > 3 or IEex_ReadByte(creatureData + 0x629, 0x0) > 2 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 2 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 4 or IEex_ReadByte(creatureData + 0x630, 0x0) > 3 or IEex_ReadByte(creatureData + 0x631, 0x0) > 2)
end
--[[
function Feats_ExtendSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local extendSpellFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_EXTEND_SPELL"], 0x0)
	if extendSpellFeatCount == 0 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 6 or IEex_ReadByte(creatureData + 0x629, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 7 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 7 or IEex_ReadByte(creatureData + 0x630, 0x0) > 5 or IEex_ReadByte(creatureData + 0x631, 0x0) > 4)
	elseif extendSpellFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 12 or IEex_ReadByte(creatureData + 0x629, 0x0) > 8 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 8 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 13 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 13 or IEex_ReadByte(creatureData + 0x630, 0x0) > 9 or IEex_ReadByte(creatureData + 0x631, 0x0) > 8)
	elseif extendSpellFeatCount == 2 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 19 or IEex_ReadByte(creatureData + 0x629, 0x0) > 12 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 12 or IEex_ReadByte(creatureData + 0x630, 0x0) > 13 or IEex_ReadByte(creatureData + 0x631, 0x0) > 12)
	elseif extendSpellFeatCount == 3 then
		return (IEex_ReadByte(creatureData + 0x629, 0x0) > 16 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 16 or IEex_ReadByte(creatureData + 0x630, 0x0) > 17 or IEex_ReadByte(creatureData + 0x631, 0x0) > 16)
	else
		return true
	end
end

function Prereq_ExtendSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local extendSpellFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_EXTEND_SPELL"], 0x0)
	if extendSpellFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 6 or IEex_ReadByte(creatureData + 0x629, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 7 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 7 or IEex_ReadByte(creatureData + 0x630, 0x0) > 5 or IEex_ReadByte(creatureData + 0x631, 0x0) > 4)
	elseif extendSpellFeatCount == 2 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 12 or IEex_ReadByte(creatureData + 0x629, 0x0) > 8 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 8 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 13 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 13 or IEex_ReadByte(creatureData + 0x630, 0x0) > 9 or IEex_ReadByte(creatureData + 0x631, 0x0) > 8)
	elseif extendSpellFeatCount == 3 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 19 or IEex_ReadByte(creatureData + 0x629, 0x0) > 12 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 12 or IEex_ReadByte(creatureData + 0x630, 0x0) > 13 or IEex_ReadByte(creatureData + 0x631, 0x0) > 12)
	elseif extendSpellFeatCount == 4 then
		return (IEex_ReadByte(creatureData + 0x629, 0x0) > 16 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 16 or IEex_ReadByte(creatureData + 0x630, 0x0) > 17 or IEex_ReadByte(creatureData + 0x631, 0x0) > 16)
	else
		return true
	end
end
--]]

function Feats_FastHealing(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local fastHealingFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_FAST_HEALING"], 0x0)
	if fastHealingFeatCount == 0 then
		return (IEex_GetActorBaseStat(actorID, 41) >= 23)
	elseif fastHealingFeatCount == 1 then
		return (IEex_GetActorBaseStat(actorID, 41) >= 25)
	elseif fastHealingFeatCount == 2 then
		return (IEex_GetActorBaseStat(actorID, 41) >= 27)
	else
		return true
	end
end

function Prereq_FastHealing(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local fastHealingFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_FAST_HEALING"], 0x0)
	if fastHealingFeatCount == 1 then
		return (IEex_GetActorBaseStat(actorID, 41) >= 23)
	elseif fastHealingFeatCount == 2 then
		return (IEex_GetActorBaseStat(actorID, 41) >= 25)
	elseif fastHealingFeatCount == 3 then
		return (IEex_GetActorBaseStat(actorID, 41) >= 27)
	else
		return true
	end
end

function Feats_Feint(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x7B6, 0x0) >= 4)
end

function Feats_ImprovedSneakAttack(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x62F, 0x0) > 4)
end

function Feats_AdvancedSpellCapacity(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local impspcFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_ADVANCED_SPELL_CAPACITY"], 0x0)
	if impspcFeatCount == 0 or impspcFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) >= 25 or IEex_ReadByte(creatureData + 0x629, 0x0) >= 19 or IEex_ReadByte(creatureData + 0x62A, 0x0) >= 19 or IEex_ReadByte(creatureData + 0x62D, 0x0) >= 20 or IEex_ReadByte(creatureData + 0x62E, 0x0) >= 20 or IEex_ReadByte(creatureData + 0x630, 0x0) >= 20 or IEex_ReadByte(creatureData + 0x631, 0x0) >= 19)
	elseif impspcFeatCount == 2 or impspcFeatCount == 3 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) >= 28 or IEex_ReadByte(creatureData + 0x629, 0x0) >= 21 or IEex_ReadByte(creatureData + 0x62A, 0x0) >= 21 or IEex_ReadByte(creatureData + 0x62D, 0x0) >= 23 or IEex_ReadByte(creatureData + 0x62E, 0x0) >= 23 or IEex_ReadByte(creatureData + 0x630, 0x0) >= 22 or IEex_ReadByte(creatureData + 0x631, 0x0) >= 21)
	elseif impspcFeatCount == 4 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) >= 31 or IEex_ReadByte(creatureData + 0x629, 0x0) >= 23 or IEex_ReadByte(creatureData + 0x62A, 0x0) >= 23 or IEex_ReadByte(creatureData + 0x62D, 0x0) >= 26 or IEex_ReadByte(creatureData + 0x62E, 0x0) >= 26 or IEex_ReadByte(creatureData + 0x630, 0x0) >= 24 or IEex_ReadByte(creatureData + 0x631, 0x0) >= 23)
	else
		return true
	end
end

function Prereq_AdvancedSpellCapacity(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local impspcFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_ADVANCED_SPELL_CAPACITY"], 0x0)
	if impspcFeatCount == 1 or impspcFeatCount == 2 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) >= 25 or IEex_ReadByte(creatureData + 0x629, 0x0) >= 19 or IEex_ReadByte(creatureData + 0x62A, 0x0) >= 19 or IEex_ReadByte(creatureData + 0x62D, 0x0) >= 20 or IEex_ReadByte(creatureData + 0x62E, 0x0) >= 20 or IEex_ReadByte(creatureData + 0x630, 0x0) >= 20 or IEex_ReadByte(creatureData + 0x631, 0x0) >= 19)
	elseif impspcFeatCount == 3 or impspcFeatCount == 4 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) >= 28 or IEex_ReadByte(creatureData + 0x629, 0x0) >= 21 or IEex_ReadByte(creatureData + 0x62A, 0x0) >= 21 or IEex_ReadByte(creatureData + 0x62D, 0x0) >= 23 or IEex_ReadByte(creatureData + 0x62E, 0x0) >= 23 or IEex_ReadByte(creatureData + 0x630, 0x0) >= 22 or IEex_ReadByte(creatureData + 0x631, 0x0) >= 21)
	elseif impspcFeatCount == 5 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) >= 31 or IEex_ReadByte(creatureData + 0x629, 0x0) >= 23 or IEex_ReadByte(creatureData + 0x62A, 0x0) >= 23 or IEex_ReadByte(creatureData + 0x62D, 0x0) >= 26 or IEex_ReadByte(creatureData + 0x62E, 0x0) >= 26 or IEex_ReadByte(creatureData + 0x630, 0x0) >= 24 or IEex_ReadByte(creatureData + 0x631, 0x0) >= 23)
	else
		return true
	end
end
--[[
function Feats_ImprovedTwoWeaponFighting(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x62E, 0x0) > 8 or (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 16 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x2) > 0 and bit.band(IEex_ReadDword(creatureData + 0x764), 0x40) > 0))
end
--]]
function Feats_ImprovedTwoWeaponFighting(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local imptwfFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_IMPROVED_TWO_WEAPON_FIGHTING"], 0x0)
	if imptwfFeatCount == 0 then
		return (IEex_ReadByte(creatureData + 0x62E, 0x0) > 8 or (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 16 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x2) > 0 and bit.band(IEex_ReadDword(creatureData + 0x764), 0x40) > 0 and IEex_GetActorBaseStat(actorID, 40) >= 17))
	elseif imptwfFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x62E, 0x0) > 14)
	else
		return true
	end
end

function Prereq_ImprovedTwoWeaponFighting(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local imptwfFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_IMPROVED_TWO_WEAPON_FIGHTING"], 0x0)
	if imptwfFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x62E, 0x0) > 8 or (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 16 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x2) > 0 and bit.band(IEex_ReadDword(creatureData + 0x764), 0x40) > 0 and IEex_GetActorBaseStat(actorID, 40) >= 17))
	elseif imptwfFeatCount == 2 then
		return (IEex_ReadByte(creatureData + 0x62E, 0x0) > 14)
	else
		return true
	end
end

function Feats_ImprovedUnarmedAbilities(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return ((bit.band(IEex_ReadDword(creatureData + 0x764), 0x8) > 0) or (bit.band(IEex_ReadDword(creatureData + 0x75C), 0x2000000) > 0))
end

function Feats_Kensei(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
--[[
--	IEex_Search_Log(1, IEex_GetGameData(), 0x7200, false)
	local g_pBaldurChitin = IEex_ReadDword(0x8CF6DC)
--	local m_pObjectGame = IEex_ReadDword(g_pBaldurChitin + 0x1C54)
	local mysteriousData = IEex_ReadDword(g_pBaldurChitin + 0x1C64)
	if mysteriousData > 0 then
		IEex_Search_Change_Log(1, mysteriousData, 0x1000, false)
		print("Searching for actorID")
		IEex_Search_Log(actorID, mysteriousData, 0x1000, false)
		print("Searching for creatureData")
		IEex_Search_Log(creatureData, mysteriousData, 0x1000, false)
	end
--]]
	return (IEex_ReadByte(creatureData + 0x626, 0x0) < 2 and IEex_ReadByte(creatureData + 0x62B, 0x0) > 0)
end

function Feats_Knockdown(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 6)
end

function Feats_Lichdom(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local lichdomFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_LICHDOM"], 0x0)
	if lichdomFeatCount >= 0 and lichdomFeatCount <= 3 then
		return (IEex_ReadByte(creatureData + 0x786, 0x0) >= 2 and bit.band(IEex_ReadByte(creatureData + 0x35, 0x0), 0x3) == 0x3 and (IEex_ReadByte(creatureData + 0x630, 0x0) > 11 or IEex_ReadByte(creatureData + 0x631, 0x0) > 11 or (IEex_ReadByte(creatureData + 0x631, 0x0) > 9 and bit.band(IEex_GetActorStat(actorID, 89), 0x1000) > 0)))
	elseif lichdomFeatCount == 4 then
		return (IEex_ReadByte(creatureData + 0x786, 0x0) >= 2 and bit.band(IEex_ReadByte(creatureData + 0x35, 0x0), 0x3) == 0x3 and (IEex_ReadByte(creatureData + 0x630, 0x0) > 19 or IEex_ReadByte(creatureData + 0x631, 0x0) > 19 or (IEex_ReadByte(creatureData + 0x631, 0x0) > 17 and bit.band(IEex_GetActorStat(actorID, 89), 0x1000) > 0)))
	else
		return true
	end
end

function Prereq_Lichdom(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local lichdomFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_LICHDOM"], 0x0)
	if lichdomFeatCount >= 1 and lichdomFeatCount <= 4 then
		return (IEex_ReadByte(creatureData + 0x786, 0x0) >= 2 and bit.band(IEex_ReadByte(creatureData + 0x35, 0x0), 0x3) == 0x3 and (IEex_ReadByte(creatureData + 0x630, 0x0) > 11 or IEex_ReadByte(creatureData + 0x631, 0x0) > 11 or (IEex_ReadByte(creatureData + 0x631, 0x0) > 9 and bit.band(IEex_GetActorStat(actorID, 89), 0x1000) > 0)))
	elseif lichdomFeatCount == 5 then
		return (IEex_ReadByte(creatureData + 0x786, 0x0) >= 2 and bit.band(IEex_ReadByte(creatureData + 0x35, 0x0), 0x3) == 0x3 and (IEex_ReadByte(creatureData + 0x630, 0x0) > 19 or IEex_ReadByte(creatureData + 0x631, 0x0) > 19 or (IEex_ReadByte(creatureData + 0x631, 0x0) > 17 and bit.band(IEex_GetActorStat(actorID, 89), 0x1000) > 0)))
	else
		return true
	end
end

function Feats_LightArmorMastery(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_GetActorBaseStat(actorID, 40) >= 17 and IEex_ReadByte(creatureData + 0x783, 0x0) > 0)
end
--[[
function Feats_Manyshot(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x62E, 0x0) > 8 or (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 16 and bit.band(IEex_ReadDword(creatureData + 0x760), 0x30000) == 0x30000))
end
--]]
function Feats_Manyshot(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local manyshotFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MANYSHOT"], 0x0)
	if manyshotFeatCount == 0 then
		return (IEex_ReadByte(creatureData + 0x62E, 0x0) > 8 or (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 16 and bit.band(IEex_ReadDword(creatureData + 0x760), 0x30000) == 0x30000 and IEex_GetActorBaseStat(actorID, 40) >= 17))
	elseif manyshotFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x62E, 0x0) > 14)
	else
		return true
	end
end

function Prereq_Manyshot(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local manyshotFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MANYSHOT"], 0x0)
	if manyshotFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x62E, 0x0) > 8 or (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 16 and bit.band(IEex_ReadDword(creatureData + 0x760), 0x30000) == 0x30000 and IEex_GetActorBaseStat(actorID, 40) >= 17))
	elseif manyshotFeatCount == 2 then
		return (IEex_ReadByte(creatureData + 0x62E, 0x0) > 14)
	else
		return true
	end
end

function Feats_MassSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x628, 0x0) > 15 or IEex_ReadByte(creatureData + 0x629, 0x0) > 10 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 10 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 16 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 16 or IEex_ReadByte(creatureData + 0x630, 0x0) > 11 or IEex_ReadByte(creatureData + 0x631, 0x0) > 10)
end

function Feats_MasterOfMagicForce(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x7C1, 0x0) >= 10 and (IEex_ReadByte(creatureData + 0x628, 0x0) > 9 or IEex_ReadByte(creatureData + 0x629, 0x0) > 6 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 6 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 10 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 10 or IEex_ReadByte(creatureData + 0x630, 0x0) > 7 or IEex_ReadByte(creatureData + 0x631, 0x0) > 6))
end

function Feats_MaximizedAttacks(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local concentrationSkill = IEex_ReadByte(creatureData + 0x7B7, 0x0)
	local numSpecializations = 0
	for i = 0x774, 0x77F, 1 do
		if IEex_ReadByte(creatureData + i, 0x0) >= 3 then
			numSpecializations = numSpecializations + 1
		end
	end
	if IEex_ReadByte(creatureData + 0x78D, 0x0) >= 3 then
		numSpecializations = numSpecializations + 1
	end
	return (numSpecializations >= 2 and concentrationSkill >= 4)
end

function Feats_MaximizeSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x628, 0x0) > 9 or IEex_ReadByte(creatureData + 0x629, 0x0) > 6 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 6 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 10 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 10 or IEex_ReadByte(creatureData + 0x630, 0x0) > 7 or IEex_ReadByte(creatureData + 0x631, 0x0) > 6)
end
--[[
function Feats_MaximizeSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local maximizeSpellFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MAXIMIZE_SPELL"], 0x0)
	if maximizeSpellFeatCount == 0 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 19 or IEex_ReadByte(creatureData + 0x629, 0x0) > 12 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 12 or IEex_ReadByte(creatureData + 0x630, 0x0) > 13 or IEex_ReadByte(creatureData + 0x631, 0x0) > 12)
	elseif maximizeSpellFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 23 or IEex_ReadByte(creatureData + 0x629, 0x0) > 14 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 14 or IEex_ReadByte(creatureData + 0x630, 0x0) > 15 or IEex_ReadByte(creatureData + 0x631, 0x0) > 14)
	elseif maximizeSpellFeatCount == 2 then
		return (IEex_ReadByte(creatureData + 0x629, 0x0) > 16 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 16 or IEex_ReadByte(creatureData + 0x630, 0x0) > 17 or IEex_ReadByte(creatureData + 0x631, 0x0) > 16)
	else
		return true
	end
end

function Prereq_MaximizeSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local maximizeSpellFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MAXIMIZE_SPELL"], 0x0)
	if maximizeSpellFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 19 or IEex_ReadByte(creatureData + 0x629, 0x0) > 12 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 12 or IEex_ReadByte(creatureData + 0x630, 0x0) > 13 or IEex_ReadByte(creatureData + 0x631, 0x0) > 12)
	elseif maximizeSpellFeatCount == 2 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 23 or IEex_ReadByte(creatureData + 0x629, 0x0) > 14 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 14 or IEex_ReadByte(creatureData + 0x630, 0x0) > 15 or IEex_ReadByte(creatureData + 0x631, 0x0) > 14)
	elseif maximizeSpellFeatCount == 3 then
		return (IEex_ReadByte(creatureData + 0x629, 0x0) > 16 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 16 or IEex_ReadByte(creatureData + 0x630, 0x0) > 17 or IEex_ReadByte(creatureData + 0x631, 0x0) > 16)
	else
		return true
	end
end
--]]
function Feats_Mobility(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_GetActorBaseStat(actorID, 40) >= 13 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x10000) > 0)
end

function Feats_NaturalSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x62A, 0x0) > 4 and IEex_ReadByte(creatureData + 0x807, 0x0) >= 13)
end

function Feats_Opportunist(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local combatReflexesCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_COMBAT_REFLEXES"], 0x0)
	return (IEex_ReadByte(creatureData + 0x62F, 0x0) > 9 and combatReflexesCount > 0)
end

function Feats_Opportunist2(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x62F, 0x0) > 9)
end

function Feats_PersistentSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x628, 0x0) > 18 or IEex_ReadByte(creatureData + 0x629, 0x0) > 12 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 12 or IEex_ReadByte(creatureData + 0x630, 0x0) > 13 or IEex_ReadByte(creatureData + 0x631, 0x0) > 12)
end
--[[
function Feats_PreciseShot(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local hasDodge = (bit.band(IEex_ReadDword(creatureData + 0x75C), 0x10000) > 0)
	local MobilityFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MOBILITY"], 0x0)
	local preciseShotFeatCount = 0
	local feats = IEex_Helper_GetBridgeNL("IEex_DerivedStatsData", IEex_GetSpriteDerivedStats(creatureData), "feats")
	local featIndex = IEex_Helper_GetBridgeNL(feats, "feat_index_"..featID)
	if featIndex then
		preciseShotFeatCount = IEex_Helper_GetBridgeNL(feats, featIndex, "count")
		if not preciseShotFeatCount then
			preciseShotFeatCount = 0
		end
	end
	if preciseShotFeatCount == 1 then
		return (hasDodge and MobilityFeatCount > 0 and IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 11)
	else
		return true
	end
end

function Prereq_PreciseShot(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local hasDodge = (bit.band(IEex_ReadDword(creatureData + 0x75C), 0x10000) > 0)
	local MobilityFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MOBILITY"], 0x0)
	local preciseShotFeatCount = 0
	local feats = IEex_Helper_GetBridgeNL("IEex_DerivedStatsData", IEex_GetSpriteDerivedStats(creatureData), "feats")
	local featIndex = IEex_Helper_GetBridgeNL(feats, "feat_index_"..featID)
	if featIndex then
		preciseShotFeatCount = IEex_Helper_GetBridgeNL(feats, featIndex, "count")
		if not preciseShotFeatCount then
			preciseShotFeatCount = 0
		end
	end
	if preciseShotFeatCount == 2 then
		return (hasDodge and MobilityFeatCount > 0 and IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 11)
	else
		return true
	end
end
--]]
function Feats_PreciseShot(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	if ex_feat_id_offset[featID] == nil then return true end
	local hasDodge = (bit.band(IEex_ReadDword(creatureData + 0x75C), 0x10000) > 0)
	local mobilityFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MOBILITY"], 0x0)
	local preciseShotFeatCount = IEex_ReadSignedByte(creatureData + ex_feat_id_offset[featID], 0x0)
	if preciseShotFeatCount == -1 then
		local hasFeat = (bit.band(IEex_ReadDword(creatureData + 0x75C), 0x200) > 0)
		if hasFeat then
			preciseShotFeatCount = 1
		else
			preciseShotFeatCount = 0
		end
		IEex_WriteByte(creatureData + ex_feat_id_offset[featID], preciseShotFeatCount)
	end
	if preciseShotFeatCount == 1 then
		return (hasDodge and mobilityFeatCount > 0 and IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 11)
	else
		return true
	end
end

function Prereq_PreciseShot(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	if ex_feat_id_offset[featID] == nil then return true end
	local hasDodge = (bit.band(IEex_ReadDword(creatureData + 0x75C), 0x10000) > 0)
	local mobilityFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MOBILITY"], 0x0)
	local preciseShotFeatCount = IEex_ReadSignedByte(creatureData + ex_feat_id_offset[featID], 0x0)
	if preciseShotFeatCount == -1 then
		local hasFeat = (bit.band(IEex_ReadDword(creatureData + 0x75C), 0x200) > 0)
		if hasFeat then
			preciseShotFeatCount = 1
		else
			preciseShotFeatCount = 0
		end
		IEex_WriteByte(creatureData + ex_feat_id_offset[featID], preciseShotFeatCount)
	end
	if preciseShotFeatCount == 2 then
		return (hasDodge and mobilityFeatCount > 0 and IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 11)
	else
		return true
	end
end

function Feats_QuickenSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x628, 0x0) > 6 or IEex_ReadByte(creatureData + 0x629, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 7 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 7 or IEex_ReadByte(creatureData + 0x630, 0x0) > 5 or IEex_ReadByte(creatureData + 0x631, 0x0) > 4)
end
--[[
function Feats_QuickenSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local quickenSpellFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_QUICKEN_SPELL"], 0x0)
	if quickenSpellFeatCount == 0 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 12 or IEex_ReadByte(creatureData + 0x629, 0x0) > 8 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 8 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 13 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 13 or IEex_ReadByte(creatureData + 0x630, 0x0) > 9 or IEex_ReadByte(creatureData + 0x631, 0x0) > 8)
	elseif quickenSpellFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 15 or IEex_ReadByte(creatureData + 0x629, 0x0) > 10 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 10 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 16 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 16 or IEex_ReadByte(creatureData + 0x630, 0x0) > 11 or IEex_ReadByte(creatureData + 0x631, 0x0) > 10)
	elseif quickenSpellFeatCount == 2 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 19 or IEex_ReadByte(creatureData + 0x629, 0x0) > 12 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 12 or IEex_ReadByte(creatureData + 0x630, 0x0) > 13 or IEex_ReadByte(creatureData + 0x631, 0x0) > 12)
	elseif quickenSpellFeatCount == 3 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 23 or IEex_ReadByte(creatureData + 0x629, 0x0) > 14 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 14 or IEex_ReadByte(creatureData + 0x630, 0x0) > 15 or IEex_ReadByte(creatureData + 0x631, 0x0) > 14)
	elseif quickenSpellFeatCount == 4 then
		return (IEex_ReadByte(creatureData + 0x629, 0x0) > 16 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 16 or IEex_ReadByte(creatureData + 0x630, 0x0) > 17 or IEex_ReadByte(creatureData + 0x631, 0x0) > 16)
	else
		return true
	end
end

function Prereq_QuickenSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local quickenSpellFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_QUICKEN_SPELL"], 0x0)
	if quickenSpellFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 12 or IEex_ReadByte(creatureData + 0x629, 0x0) > 8 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 8 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 13 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 13 or IEex_ReadByte(creatureData + 0x630, 0x0) > 9 or IEex_ReadByte(creatureData + 0x631, 0x0) > 8)
	elseif quickenSpellFeatCount == 2 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 15 or IEex_ReadByte(creatureData + 0x629, 0x0) > 10 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 10 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 16 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 16 or IEex_ReadByte(creatureData + 0x630, 0x0) > 11 or IEex_ReadByte(creatureData + 0x631, 0x0) > 10)
	elseif quickenSpellFeatCount == 3 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 19 or IEex_ReadByte(creatureData + 0x629, 0x0) > 12 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 12 or IEex_ReadByte(creatureData + 0x630, 0x0) > 13 or IEex_ReadByte(creatureData + 0x631, 0x0) > 12)
	elseif quickenSpellFeatCount == 4 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 23 or IEex_ReadByte(creatureData + 0x629, 0x0) > 14 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 14 or IEex_ReadByte(creatureData + 0x630, 0x0) > 15 or IEex_ReadByte(creatureData + 0x631, 0x0) > 14)
	elseif quickenSpellFeatCount == 5 then
		return (IEex_ReadByte(creatureData + 0x629, 0x0) > 16 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 16 or IEex_ReadByte(creatureData + 0x630, 0x0) > 17 or IEex_ReadByte(creatureData + 0x631, 0x0) > 16)
	else
		return true
	end
end
--]]
function Feats_RapidReload(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 6 and IEex_ReadByte(creatureData + 0x775, 0x0) >= 2)
end

function Feats_SafeSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x628, 0x0) > 3 or IEex_ReadByte(creatureData + 0x629, 0x0) > 2 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 2 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 4 or IEex_ReadByte(creatureData + 0x630, 0x0) > 3 or IEex_ReadByte(creatureData + 0x631, 0x0) > 2)
end
--[[
function Feats_SafeSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local safeSpellFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_SAFE_SPELL"], 0x0)
	if safeSpellFeatCount == 0 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 6 or IEex_ReadByte(creatureData + 0x629, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 7 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 7 or IEex_ReadByte(creatureData + 0x630, 0x0) > 5 or IEex_ReadByte(creatureData + 0x631, 0x0) > 4)
	elseif safeSpellFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 12 or IEex_ReadByte(creatureData + 0x629, 0x0) > 8 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 8 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 13 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 13 or IEex_ReadByte(creatureData + 0x630, 0x0) > 9 or IEex_ReadByte(creatureData + 0x631, 0x0) > 8)
	elseif safeSpellFeatCount == 2 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 19 or IEex_ReadByte(creatureData + 0x629, 0x0) > 12 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 12 or IEex_ReadByte(creatureData + 0x630, 0x0) > 13 or IEex_ReadByte(creatureData + 0x631, 0x0) > 12)
	elseif safeSpellFeatCount == 3 then
		return (IEex_ReadByte(creatureData + 0x629, 0x0) > 16 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 16 or IEex_ReadByte(creatureData + 0x630, 0x0) > 17 or IEex_ReadByte(creatureData + 0x631, 0x0) > 16)
	else
		return true
	end
end

function Prereq_SafeSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local safeSpellFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_SAFE_SPELL"], 0x0)
	if safeSpellFeatCount == 1 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 6 or IEex_ReadByte(creatureData + 0x629, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 7 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 7 or IEex_ReadByte(creatureData + 0x630, 0x0) > 5 or IEex_ReadByte(creatureData + 0x631, 0x0) > 4)
	elseif safeSpellFeatCount == 2 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 12 or IEex_ReadByte(creatureData + 0x629, 0x0) > 8 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 8 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 13 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 13 or IEex_ReadByte(creatureData + 0x630, 0x0) > 9 or IEex_ReadByte(creatureData + 0x631, 0x0) > 8)
	elseif safeSpellFeatCount == 3 then
		return (IEex_ReadByte(creatureData + 0x628, 0x0) > 19 or IEex_ReadByte(creatureData + 0x629, 0x0) > 12 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 12 or IEex_ReadByte(creatureData + 0x630, 0x0) > 13 or IEex_ReadByte(creatureData + 0x631, 0x0) > 12)
	elseif safeSpellFeatCount == 4 then
		return (IEex_ReadByte(creatureData + 0x629, 0x0) > 16 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 16 or IEex_ReadByte(creatureData + 0x630, 0x0) > 17 or IEex_ReadByte(creatureData + 0x631, 0x0) > 16)
	else
		return true
	end
end
--]]
function Feats_ShieldFocus(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	if bit.band(IEex_ReadDword(creatureData + 0x760), 0x100000) == 0 then
		return false
	else
		local shieldFocusFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_SHIELD_FOCUS"], 0x0)
		return (shieldFocusFeatCount == 0 or IEex_ReadByte(creatureData + 0x62B, 0x0) > 3)
	end
end

function Prereq_ShieldFocus(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	if bit.band(IEex_ReadDword(creatureData + 0x760), 0x100000) == 0 then
		return false
	else
		local shieldFocusFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_SHIELD_FOCUS"], 0x0)
		return (shieldFocusFeatCount <= 1 or IEex_ReadByte(creatureData + 0x62B, 0x0) > 3)
	end
end

function Feats_SpringAttack(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_GetActorBaseStat(actorID, 40) >= 13 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x10000) > 0 and IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MOBILITY"], 0x0) > 0 and IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 4)
end

function Feats_TerrifyingRage(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x627, 0x0) > 14 and IEex_ReadByte(creatureData + 0x7BB, 0x0) >= 18)
end

function Feats_TwoWeaponDefense(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x62E, 0x0) > 0 or bit.band(IEex_ReadDword(creatureData + 0x764), 0x40) > 0)
end

function Feats_WeaponProficiency(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	if ex_feat_id_offset[featID] == nil then return true end
	local weaponProficiencyFeatCount = IEex_ReadByte(creatureData + ex_feat_id_offset[featID], 0x0)
	local fighterLevel = IEex_ReadByte(creatureData + 0x62B, 0x0)
	if weaponProficiencyFeatCount == 2 then
		return (fighterLevel >= 4)
	elseif weaponProficiencyFeatCount == 3 then
		return (fighterLevel >= 8)
	elseif weaponProficiencyFeatCount == 4 then
		return (fighterLevel >= 12)
	else
		return true
	end
end

function Prereq_WeaponProficiency(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	if ex_feat_id_offset[featID] == nil then return true end
	local weaponProficiencyFeatCount = IEex_ReadByte(creatureData + ex_feat_id_offset[featID], 0x0)
	local fighterLevel = IEex_ReadByte(creatureData + 0x62B, 0x0)
	if weaponProficiencyFeatCount == 3 then
		return (fighterLevel >= 4)
	elseif weaponProficiencyFeatCount == 4 then
		return (fighterLevel >= 8)
	elseif weaponProficiencyFeatCount == 5 then
		return (fighterLevel >= 12)
	else
		return true
	end
end

function Feats_WhirlwindAttack(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local whirlwindAttackFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_WHIRLWIND_ATTACK"], 0x0)
	if whirlwindAttackFeatCount == 0 then
		return (IEex_GetActorBaseStat(actorID, 40) >= 13 and (IEex_ReadByte(creatureData + 0x62E, 0x0) > 5 or (IEex_ReadByte(creatureData + 0x803, 0x0) >= 13 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x10000) > 0 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x80000) > 0 and IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MOBILITY"], 0x0) > 0 and IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_SPRING_ATTACK"], 0x0) > 0 and IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 4)))
	elseif whirlwindAttackFeatCount == 1 then
		return (IEex_GetActorBaseStat(actorID, 40) >= 21 and (IEex_ReadByte(creatureData + 0x62E, 0x0) > 5 or (IEex_ReadByte(creatureData + 0x803, 0x0) >= 13 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x10000) > 0 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x80000) > 0 and IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MOBILITY"], 0x0) > 0 and IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_SPRING_ATTACK"], 0x0) > 0 and IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 4)))
	elseif whirlwindAttackFeatCount == 2 then
		return (IEex_GetActorBaseStat(actorID, 40) >= 25 and IEex_ReadByte(creatureData + 0x62E, 0x0) > 29)
	else
		return true
	end
end

function Prereq_WhirlwindAttack(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	local whirlwindAttackFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_WHIRLWIND_ATTACK"], 0x0)
	if whirlwindAttackFeatCount == 1 then
		return (IEex_GetActorBaseStat(actorID, 40) >= 13 and (IEex_ReadByte(creatureData + 0x62E, 0x0) > 5 or (IEex_ReadByte(creatureData + 0x803, 0x0) >= 13 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x10000) > 0 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x80000) > 0 and IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MOBILITY"], 0x0) > 0 and IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_SPRING_ATTACK"], 0x0) > 0 and IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 4)))
	elseif whirlwindAttackFeatCount == 2 then
		return (IEex_GetActorBaseStat(actorID, 40) >= 21 and (IEex_ReadByte(creatureData + 0x62E, 0x0) > 5 or (IEex_ReadByte(creatureData + 0x803, 0x0) >= 13 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x10000) > 0 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x80000) > 0 and IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MOBILITY"], 0x0) > 0 and IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_SPRING_ATTACK"], 0x0) > 0 and IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 4)))
	elseif whirlwindAttackFeatCount == 3 then
		return (IEex_GetActorBaseStat(actorID, 40) >= 25 and IEex_ReadByte(creatureData + 0x62E, 0x0) > 29)
	else
		return true
	end
end

function Feats_WidenSpell(actorID, featID)
	local creatureData = IEex_GetActorShare(actorID)
	return (IEex_ReadByte(creatureData + 0x628, 0x0) > 3 or IEex_ReadByte(creatureData + 0x629, 0x0) > 2 or IEex_ReadByte(creatureData + 0x62A, 0x0) > 2 or IEex_ReadByte(creatureData + 0x62D, 0x0) > 4 or IEex_ReadByte(creatureData + 0x62E, 0x0) > 4 or IEex_ReadByte(creatureData + 0x630, 0x0) > 3 or IEex_ReadByte(creatureData + 0x631, 0x0) > 2)
end

------------------------------------------------------------
-- Functions which can be used by Opcode 500 (Invoke Lua) --
------------------------------------------------------------

function B3FEAT(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
end

-- Changes the actionbar button at index [parameter1]
--  to the type in [parameter2].
function EXBUTTON(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local currentButtonState = IEex_ReadDword(creatureData + 0x3D14 + parameter1 * 0x4)
	if bit.band(internalFlags, 0x10) == 0 or sourceID <= 0 or currentButtonState == 100 then
		IEex_WriteDword(effectData + 0x10C, targetID)
		IEex_WriteDword(effectData + 0xD4, bit.bor(internalFlags, 0x10))
		IEex_SetActionbarButton(targetID, parameter1, parameter2)
	end
end

-- Does a search through the creature's data for the
--  number specified by parameter1. Each time it finds the number,
--  it prints the value's offset from the beginning of the creature data.
--  The special parameter determines the number of bytes to search. If the
--  save bonus parameter is greater than 0, it searches for an 8-character string
--  rather than a number.
-- This function can be used to find where a certain stat is stored in the creature's data.
function EXSEARCH(effectData, creatureData)
	local is_string = IEex_ReadDword(effectData + 0x40)
	local search_start = IEex_ReadDword(effectData + 0x1C)
	local search_length = IEex_ReadDword(effectData + 0x44)
	if is_string > 0 then
		local search_target = IEex_ReadLString(effectData + 0x18, 0x8)
		for i = 0, search_length, 1 do
			if IEex_ReadLString(creatureData + i, 0x8) == search_target then
				IEex_DisplayString("Match found for " .. search_target .. " at offset " .. i)
			end
		end
	else
		local search_byte = IEex_ReadByte(effectData + 0x18, 0x0)
		local search_word = IEex_ReadWord(effectData + 0x18, 0x0)
		local search_dword = IEex_ReadDword(effectData + 0x18)
		for i = 0, search_length, 1 do
			if IEex_ReadDword(creatureData + i) == search_dword then
				IEex_DisplayString("Match found for " .. search_dword .. " at offset " .. i .. " (4 bytes)")
			elseif search_dword < 65536 and IEex_ReadWord(creatureData + i, 0x0) == search_word then
				IEex_DisplayString("Match found for " .. search_word .. " at offset " .. i .. " (2 bytes)")
			elseif search_dword < 256 and IEex_ReadByte(creatureData + i, 0x0) == search_byte then
				IEex_DisplayString("Match found for " .. search_byte .. " at offset " .. i .. " (1 byte)")
			end
		end
	end
end

ex_search_previous = {}
ex_search_exclude = {}
function IEex_Search_Change(read_size, search_start, search_length, noise_reduction)
	for i = 0, search_length, 1 do
		local previous = ex_search_previous["" .. i]
		local current = IEex_ReadSignedByte(search_start + i, 0x0)
		if read_size == 2 then
			current = IEex_ReadSignedWord(search_start + i, 0x0)
		elseif read_size == 4 then
			current = IEex_ReadDword(search_start + i)
		end
		if previous ~= nil and previous ~= current and ex_search_exclude["" .. i] == nil then
			IEex_DisplayString(IEex_ToHex(i, 0, true) .. ": Changed from " .. previous .. " to " .. current)
			if noise_reduction == true then
				ex_search_exclude["" .. i] = true
			end
		end
		ex_search_previous["" .. i] = current
	end
end

function IEex_Search_Change_Log(read_size, search_start, search_length, noise_reduction)
	for i = 0, search_length, 1 do
		local previous = ex_search_previous["" .. i]
		local current = IEex_ReadSignedByte(search_start + i, 0x0)
		if read_size == 2 then
			current = IEex_ReadSignedWord(search_start + i, 0x0)
		elseif read_size == 4 then
			current = IEex_ReadDword(search_start + i)
		end
		if previous ~= nil and previous ~= current and ex_search_exclude["" .. i] == nil then
			print(IEex_ToHex(i, 0, true) .. ": Changed from " .. previous .. " to " .. current)
			if noise_reduction == true then
				ex_search_exclude["" .. i] = true
			end
		end
		ex_search_previous["" .. i] = current
	end
end

function EXPRINTO(effectData, creatureData)
	local offset = IEex_ReadDword(effectData + 0x1C)
	local read_size = IEex_ReadDword(effectData + 0x40)
	if read_size == 1 then
		IEex_DisplayString("Byte at offset " .. offset .. " is " .. IEex_ReadByte(creatureData + offset, 0x0))
	elseif read_size == 2 then
		IEex_DisplayString("Word at offset " .. offset .. " is " .. IEex_ReadWord(creatureData + offset, 0x0))
	elseif read_size == 4 or read_size == 0 then
		IEex_DisplayString("Dword at offset " .. offset .. " is " .. IEex_ReadDword(creatureData + offset))
	else
		IEex_DisplayString("String at offset " .. offset .. " is " .. IEex_ReadLString(creatureData + offset, 0x8))
	end
end

function EXPRINTS(effectData, creatureData)
	local starting = IEex_ReadDword(effectData + 0x1C)
	local ending = IEex_ReadDword(effectData + 0x44)
	for i = starting, ending, 1 do
		IEex_DisplayString(IEex_ToHex(i, 0, true) .. ": " .. IEex_ReadByte(creatureData + i, 0x0) .. ", " .. IEex_ReadWord(creatureData + i, 0x0) .. ", " .. IEex_ReadDword(creatureData + i) .. ", \"" .. IEex_ReadLString(creatureData + i, 8) .. "\"")
	end
end

function IEex_Search(search_target, search_start, search_length, noise_reduction)
	if type(search_target) == "string" then
		for i = 0, search_length, 1 do
			if IEex_ReadLString(search_start + i, 0x8) == search_target and ex_search_exclude["" .. i] == nil then
				IEex_DisplayString("Match found for " .. search_target .. " at offset " .. IEex_ToHex(i, 0, false))
				if noise_reduction == true then
					ex_search_exclude["" .. i] = true
				end
			end
		end
	else
		for i = 0, search_length, 1 do
			if ex_search_exclude["" .. i] == nil then
				if IEex_ReadDword(search_start + i) == search_target then
					IEex_DisplayString("Match found for " .. search_target .. " at offset " .. IEex_ToHex(i, 0, false) .. " (4 bytes)")
				elseif search_target < 65536 and IEex_ReadWord(search_start + i, 0x0) == search_target then
					IEex_DisplayString("Match found for " .. search_target .. " at offset " .. IEex_ToHex(i, 0, false) .. " (2 bytes)")
				elseif search_target < 256 and IEex_ReadByte(search_start + i, 0x0) == search_target then
					IEex_DisplayString("Match found for " .. search_target .. " at offset " .. IEex_ToHex(i, 0, false) .. " (1 byte)")
				end
				if noise_reduction == true then
					ex_search_exclude["" .. i] = true
				end
			end
		end
	end
end

function IEex_Search_Log(search_target, search_start, search_length, noise_reduction)
	if type(search_target) == "string" then
		for i = 0, search_length, 1 do
			if IEex_ReadLString(search_start + i, 0x8) == search_target and ex_search_exclude["" .. i] == nil then
				print("Match found for " .. search_target .. " at offset " .. IEex_ToHex(i, 0, false))
				if noise_reduction == true then
					ex_search_exclude["" .. i] = true
				end
			end
		end
	else
		for i = 0, search_length, 1 do
			if ex_search_exclude["" .. i] == nil then
				if IEex_ReadDword(search_start + i) == search_target then
					print("Match found for " .. search_target .. " at offset " .. IEex_ToHex(i, 0, false) .. " (4 bytes)")
				elseif search_target < 65536 and IEex_ReadWord(search_start + i, 0x0) == search_target then
					print("Match found for " .. search_target .. " at offset " .. IEex_ToHex(i, 0, false) .. " (2 bytes)")
				elseif search_target < 256 and IEex_ReadByte(search_start + i, 0x0) == search_target then
					print("Match found for " .. search_target .. " at offset " .. IEex_ToHex(i, 0, false) .. " (1 byte)")
				end
				if noise_reduction == true then
					ex_search_exclude["" .. i] = true
				end
			end
		end
	end
end

function IEex_PrintData(search_start, search_length)
	for i = 0, search_length, 1 do
		IEex_DisplayString(IEex_ToHex(i, 0, true) .. ": " .. IEex_ReadByte(search_start + i, 0x0) .. ", " .. IEex_ReadWord(search_start + i, 0x0) .. ", " .. IEex_ReadDword(search_start + i) .. ", \"" .. IEex_ReadLString(search_start + i, 8) .. "\"")
	end
end

function IEex_PrintData_Log(search_start, search_length)
	for i = 0, search_length, 1 do
		print(IEex_ToHex(i, 0, true) .. ": " .. IEex_ReadByte(search_start + i, 0x0) .. ", " .. IEex_ReadWord(search_start + i, 0x0) .. ", " .. IEex_ReadDword(search_start + i) .. ", \"" .. IEex_ReadLString(search_start + i, 8) .. "\"")
	end
end

ex_order_multiclass = {
[1] = {{3, 0x8000}, {6, 0x10}, {7, -1}},
[2] = {{3, 0x40000}, {5, -1}, {7, -1}},
[4] = {{7, -1}, {10, -1}, {11, -1}},
[8] = {{4, -1}, {6, -1}, {9, -1}},
[16] = {{3, 0x8000}, {6, -1}, {7, 0x1}},
[32] = {{6, -1}, {9, -1}, {10, -1}}
}

--[[
To use the EXDAMAGE function, create an opcode 500 effect in an item or spell, set the resource to EXDAMAGE (all capitals),
 set the timing to instant, limited and the duration to 0, and choose parameters.

The EXDAMAGE function deals damage to the target. The main use of it is to put it on a weapon that should deal non-physical
 damage, such as the Flame Blade. The function can add bonuses to the damage dealt based on the character's Strength, proficiencies,
 and general weapon damage bonuses. This can't be done simply by applying a damage effect normally.

parameter1 - The first byte determines the damage, the second byte determines the dice size, the third byte determines the dice number,
 and the fourth byte determines the feat ID of the proficiency used. For example, if the effect is from a greatsword and should do 2d6+3 damage,
 parameter1 should be this:
 0x29020603
 0x29 is the Martial Weapon: Greatsword feat ID, 0x2 is the dice number, 0x6 is the dice size, and 0x3 is the damage bonus.
 If a proficiency is not specified, it doesn't give a damage bonus based on proficiency.

parameter2 - It's the same as parameter2 on the damage opcode: the first two bytes determine whether to just deal damage or set HP or whatever.
 The last two bytes determine the damage type. If you simply want to deal fire damage, parameter2 would be 0x80000.

savingthrow - This function uses several extra bits on this parameter:
Bit 10: If set, there is a Fortitude saving throw to prevent/halve the damage.
Bit 11: If set, there is a Reflex saving throw to prevent/halve the damage.
Bit 12: If set, there is a Will saving throw to prevent/halve the damage.
Bit 16: If set, the damage is multiplied by opcode 73 (when parameter2 > 0).
Bit 17: If set, the damage is treated as the base damage of a melee weapon, so it gets damage bonuses from opcode 73 (when parameter2 = 0) and Power Attack.
Bit 18: If set, the damage is treated as the base damage of a missile weapon, so it gets damage bonuses from opcode 73 (when parameter2 = 0).
If both bits 17 and 18 are set, opcode 73 damage bonuses are not applied multiple times. Also, if at least one
 of those two bits are set, the minimum damage of each die will be increased based on the source character's Luck bonuses.
 If neither of those two bits are set, the maximum damage of each die is decreased based on the target character's Luck bonuses.
Bit 19: If set, the character's Sneak Attack dice will be added to the damage if the conditions for a Sneak Attack are met. Bit 17, 18 or 23 must be set for a sneak attack to happen, unless the character has a "Sneak Attack with Spells" effect.
Bit 21: If set, the character gains temporary Hit Points (for 1 hour) equal to the damage dealt.
Bit 22: If set, the character regains Hit Points equal to the damage dealt (but will not go over the character's max HP).
Bit 23: If set, the damage can count as a Sneak Attack even if Bits 17 and 18 are not set.
Bit 24: If set, no damage will be dealt except on a successful Sneak Attack.
Bit 25: If set, the damage will be reduced by the target's damage reduction if the damage's enchantment level (specified in the fourth bit of special) is too low.
Bit 26: If set, the damage bypasses Mirror Image.

savebonus - The saving throw DC bonus of the damage is equal to that of the opcode 500 effect.

special - The first byte determines which stat should be used to determine an extra damage bonus (e.g. for Strength weapons, this would be stat 36 or 0x24: the Strength stat).
 If set to 0, there is no stat-based damage bonus. If the chosen stat is an ability score, the bonus will be based on the ability score bonus (e.g. 16 Strength would translate to +3);
 otherwise, the bonus is equal to the stat. The second byte determines a multiplier to the stat-based damage bonus, while the third byte determines a divisor to it (for example,
 if the damage was from a two-handed Strength weapon, special would be equal to 0x20324: the Strength bonus is multiplied by 3 then divided by 2 to get the damage bonus). If the
 multiplier or divisor is 0, the function sets it to 1.
--]]
ex_item_type_proficiency = {[5] = 39, [14] = 55, [15] = 39, [16] = 57, [17] = 54, [18] = 55, [19] = 57, [20] = 43, [21] = 42, [22] = 54, [23] = 40, [24] = 55, [25] = 38, [26] = 56, [27] = 53, [29] = 44, [30] = 44, [31] = 53, [44] = 4, [57] = 41, [69] = 18}
ex_item_type_critical = {[0] = {0, 2}, [5] = {0, 3}, [14] = {0, 2}, [15] = {0, 3}, [16] = {1, 2}, [17] = {0, 2}, [18] = {0, 2}, [19] = {1, 2}, [20] = {1, 2}, [21] = {0, 3}, [22] = {0, 3}, [23] = {0, 3}, [24] = {0, 2}, [25] = {0, 3}, [26] = {0, 2}, [27] = {0, 2}, [28] = {0, 2}, [29] = {0, 3}, [30] = {0, 3}, [31] = {0, 2}, [44] = {0, 2}, [57] = {1, 2}, [69] = {1, 2}}
ex_crippling_strike = {ex_tra_905, ex_tra_905, ex_tra_905, ex_tra_905, ex_tra_905, ex_tra_906, ex_tra_906, ex_tra_906, ex_tra_907, ex_tra_907, ex_tra_907, ex_tra_908, ex_tra_908, ex_tra_908, ex_tra_909, ex_tra_909, ex_tra_909, ex_tra_910, ex_tra_910, ex_tra_910, ex_tra_911, ex_tra_911, ex_tra_911, ex_tra_912, ex_tra_912, ex_tra_912, ex_tra_913, ex_tra_913, ex_tra_913, ex_tra_914}
ex_crippling_strike_assassin = {ex_tra_930, ex_tra_930, ex_tra_930, ex_tra_930, ex_tra_930, ex_tra_931, ex_tra_931, ex_tra_931, ex_tra_932, ex_tra_932, ex_tra_932, ex_tra_933, ex_tra_933, ex_tra_933, ex_tra_934, ex_tra_934, ex_tra_934, ex_tra_935, ex_tra_935, ex_tra_935, ex_tra_936, ex_tra_936, ex_tra_936, ex_tra_937, ex_tra_937, ex_tra_937, ex_tra_938, ex_tra_938, ex_tra_938, ex_tra_939}
ex_arterial_strike = {1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5}
ex_feat_id_offset = {[9] = 0x70C, [48] = 0x70D, [16] = 0x70E, [18] = 0x78D, [38] = 0x777, [39] = 0x774, [40] = 0x779, [41] = 0x77D, [42] = 0x77B, [43] = 0x77E, [44] = 0x77A, [53] = 0x775, [54] = 0x778, [55] = 0x776, [56] = 0x77C, [57] = 0x77F}
ex_damage_multiplier_type = {[0] = 9, [0x10000] = 4, [0x20000] = 2, [0x40000] = 3, [0x80000] = 1, [0x100000] = 8, [0x200000] = 6, [0x400000] = 5, [0x800000] = 10, [0x1000000] = 7, [0x2000000] = 10, [0x4000000] = 10, [0x8000000] = 9, [0x10000000] = 5}
ex_damage_resistance_opcode = {[0] = 87, [0x10000] = 27, [0x20000] = 28, [0x40000] = 29, [0x80000] = 30, [0x100000] = 88, [0x200000] = 173, [0x400000] = 31, [0x800000] = 89, [0x1000000] = 86, [0x2000000] = 88, [0x4000000] = 87, [0x8000000] = 87, [0x10000000] = 31}
ex_damage_resistance_stat = {[0] = 22, [0x10000] = 17, [0x20000] = 15, [0x40000] = 16, [0x80000] = 14, [0x100000] = 23, [0x200000] = 74, [0x400000] = 73, [0x800000] = 24, [0x1000000] = 21, [0x2000000] = 19, [0x4000000] = 20, [0x8000000] = 22, [0x10000000] = 73}
ex_damage_resistance_stat_offset = {[0] = 0x952, [0x10000] = 0x948, [0x20000] = 0x944, [0x40000] = 0x946, [0x80000] = 0x942, [0x100000] = 0x954, [0x200000] = 0x9DA, [0x400000] = 0x9D8, [0x800000] = 0x956, [0x1000000] = 0x950, [0x2000000] = 0x954, [0x4000000] = 0x952, [0x8000000] = 0x952, [0x10000000] = 0x9D8}
function EXDAMAGE(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceData = IEex_GetActorShare(sourceID)
	local damage = IEex_ReadSignedByte(effectData + 0x18, 0x0)
	local dicesize = IEex_ReadByte(effectData + 0x19, 0x0)
	local dicenumber = IEex_ReadByte(effectData + 0x1A, 0x0)
	if dicenumber == 0 then
		damage = IEex_ReadByte(effectData + 0x18, 0x0)
	end
	local proficiency = IEex_ReadByte(effectData + 0x1B, 0x0)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local parameter3 = IEex_ReadDword(effectData + 0x5C)
	local parameter4 = IEex_ReadDword(effectData + 0x60)
	local damageType = bit.band(parameter2, 0xFFFF0000)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local savebonus = IEex_ReadDword(effectData + 0x40)
	local bonusStat = IEex_ReadByte(effectData + 0x44, 0x0)
	local bonusStatMultiplier = IEex_ReadByte(effectData + 0x45, 0x0)
	local bonusStatDivisor = IEex_ReadByte(effectData + 0x46, 0x0)
	local saveBonusStat = IEex_ReadByte(effectData + 0x47, 0x0)
	local launcherRES = ""
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	local casterDomain = IEex_ReadByte(effectData + 0xC6, 0x0)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local sourceSpell = ex_source_spell[parent_resource]
	if sourceSpell == nil then
		sourceSpell = parent_resource
	end
	local classSpellLevel = 0
	if IEex_IsSprite(sourceID, true) then
		classSpellLevel = IEex_GetClassSpellLevel(sourceID, casterClass, sourceSpell)
	end
	if classSpellLevel <= 0 then
		local resWrapper = IEex_DemandRes(sourceSpell, "SPL")
		if resWrapper:isValid() then
			local spellData = resWrapper:getData()
			if IEex_ReadWord(spellData + 0x1C, 0x0) == 1 or IEex_ReadWord(spellData + 0x1C, 0x0) == 2 then
				classSpellLevel = IEex_ReadDword(spellData + 0x34)
			end
		end
		resWrapper:free()
	end
	savebonus = savebonus + classSpellLevel
	local trueschool = 0
	if ex_trueschool[sourceSpell] ~= nil then
		trueschool = ex_trueschool[sourceSpell]
	end
	if trueschool > 0 then
		local sourceKit = IEex_GetActorStat(sourceID, 89)
		if bit.band(sourceKit, 0x4000) > 0 then
			savebonus = savebonus + 1
		elseif ex_spell_focus_component_installed then
			if bit.band(savingthrow, 0x2000) == 0 then
				if trueschool == 1 and bit.band(sourceKit, 0x40) > 0 or trueschool == 2 and bit.band(sourceKit, 0x80) > 0 or trueschool == 3 and bit.band(sourceKit, 0x100) > 0 or trueschool == 5 and bit.band(sourceKit, 0x400) > 0 then
					savebonus = savebonus + 2
				elseif trueschool == 1 and bit.band(sourceKit, 0x2000) > 0 or trueschool == 2 and bit.band(sourceKit, 0x800) > 0 or trueschool == 3 and bit.band(sourceKit, 0x1000) > 0 or trueschool == 5 and bit.band(sourceKit, 0x200) > 0 then
					savebonus = savebonus - 2
				end
			else
				if trueschool == 1 and bit.band(sourceKit, 0x40) > 0 or trueschool == 2 and bit.band(sourceKit, 0x80) > 0 or trueschool == 3 and bit.band(sourceKit, 0x100) > 0 or trueschool == 4 and bit.band(sourceKit, 0x200) > 0 or trueschool == 5 and bit.band(sourceKit, 0x400) > 0 or trueschool == 6 and bit.band(sourceKit, 0x800) > 0 or trueschool == 7 and bit.band(sourceKit, 0x1000) > 0 or trueschool == 8 and bit.band(sourceKit, 0x2000) > 0 then
					savebonus = savebonus + 2
				end
			end
		end
	end
	local rogueLevel = 0
	local sneakAttackDiceNumber = 0
	local isSneakAttack = false
	local isTrueBackstab = false
	if IEex_IsSprite(sourceID, true) then
		local alignment = IEex_ReadByte(sourceData + 0x35, 0x0)
		if bit.band(alignment, 0x3) == 0x3 and IEex_GetActorSpellState(targetID, 1) then
			savebonus = savebonus - 2
		end
		local weaponSlot = IEex_ReadByte(sourceData + 0x4BA4, 0x0)
		if weaponSlot >= 11 and weaponSlot <= 14 then
			IEex_IterateActorEffects(sourceID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				local thegeneralitemcategory = IEex_ReadByte(eData + 0x48, 0x0)
				if theopcode == 288 and theparameter2 == 241 and thegeneralitemcategory == 7 then
					launcherRES = IEex_ReadLString(eData + 0x94, 8)
				end
			end)
		end
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if theopcode == 502 and theresource == "MESVVTYP" then
				if (theparameter2 == 2 and IEex_ReadByte(creatureData + 0x24, 0x0) == theparameter1) or (theparameter2 == 3 and IEex_ReadByte(creatureData + 0x25, 0x0) == theparameter1) or (theparameter2 == 4 and IEex_ReadByte(creatureData + 0x26, 0x0) == theparameter1) or (theparameter2 == 5 and bit.band(IEex_ReadDword(creatureData + 0x38), theparameter1) > 0) or (theparameter2 == 6 and IEex_ReadByte(creatureData + 0x27, 0x0) == theparameter1) or (theparameter2 == 7 and IEex_ReadByte(creatureData + 0x34, 0x0) == theparameter1) then
					savebonus = savebonus - thespecial
				elseif theparameter2 == 8 then
					if alignment == theparameter1 or bit.band(alignment, 0x3) == theparameter1 or bit.band(alignment, 0x30) == theparameter1 then
						savebonus = savebonus - thespecial
					end
				end
			end
		end)
		if bit.band(savingthrow, 0x40) > 0 then
			savebonus = savebonus + IEex_ReadByte(sourceData + 0x784, 0x0) * 2
		end
		if bit.band(savingthrow, 0x80) > 0 then
			savebonus = savebonus + IEex_ReadByte(sourceData + 0x785, 0x0) * 2
		end
		if bit.band(savingthrow, 0x100) > 0 then
			savebonus = savebonus + IEex_ReadByte(sourceData + 0x786, 0x0) * 2
		end
		if bit.band(savingthrow, 0x200) > 0 then
			savebonus = savebonus + IEex_ReadByte(sourceData + 0x787, 0x0) * 2
		end
		if proficiency > 0 and ex_feat_id_offset[proficiency] ~= nil then
			local proficiencyDamage = tonumber(IEex_2DAGetAtStrings("WSPECIAL", "DAMAGE", tostring(IEex_ReadByte(sourceData + ex_feat_id_offset[proficiency], 0x0))))
--			local proficiencyDamage = ex_proficiency_damage[IEex_ReadByte(sourceData + ex_feat_id_offset[proficiency], 0x0)]
			if proficiencyDamage ~= nil then
				damage = damage + proficiencyDamage
			end
		end
		if bit.band(savingthrow, 0x20000) > 0 or (bit.band(internalFlags, 0x1000) > 0 and ex_melee_touch_attacks_use_power_attack) then
			for i = 1, 5, 1 do
				if IEex_GetActorSpellState(sourceID, i + 75) then
					damage = damage + i
				end
			end
		end
		if IEex_GetActorSpellState(sourceID, 233) and bit.band(savingthrow, 0x20000) == 0 and bit.band(savingthrow, 0x40000) == 0 and (bit.band(savingthrow, 0x800000) == 0 or bit.band(internalFlags, 0x3000) > 0) then
			damage = damage + math.floor((IEex_GetActorStat(sourceID, 36) - 10) / 4)
		end
		rogueLevel = IEex_GetActorStat(sourceID, 104)
		local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
		if (rogueLevel > 0 or IEex_GetActorSpellState(sourceID, 192)) then
			local isSleeping = false
			local isImmuneToSneakAttack = false
			local isNotImmuneToSneakAttack = false
			local canSneakAttackOnNextHit = false
			local canSneakAttackOnEveryHit = false
			local canSneakAttackWithSpells = false
			IEex_IterateActorEffects(sourceID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				local thespecial = IEex_ReadDword(eData + 0x48)
				if theopcode == 288 and theparameter2 == 216 then
					if thespecial == 2 then
						canSneakAttackOnNextHit = true
					elseif thespecial == 3 then
						canSneakAttackOnEveryHit = true
					elseif thespecial == 5 then
						canSneakAttackWithSpells = true
					end
				end
			end)
			IEex_IterateActorEffects(targetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				local thespecial = IEex_ReadDword(eData + 0x48)
				if theopcode == 288 and theparameter2 == 216 then
					if thespecial == 0 then
						isImmuneToSneakAttack = true
					elseif thespecial == 1 then
						isNotImmuneToSneakAttack = true
					elseif thespecial == 4 then
						isSleeping = true
					end
				end
			end)
			if bit.band(internalFlags, 0x800) > 0 then
				canSneakAttackOnNextHit = true
			end
			if ex_anyone_immune_to_critical_hits_is_immune_to_sneak_attacks and bit.band(IEex_ReadByte(creatureData + 0x89F, 0x0), 0x2) > 0 then
				isImmuneToSneakAttack = true
			end
			if isNotImmuneToSneakAttack then
				isImmuneToSneakAttack = false
			end
			local uncannyDodgeLevel = 0
			if (IEex_GetActorStat(targetID, 96) >= ex_improved_uncanny_dodge_class_level[1] or IEex_GetActorStat(targetID, 104) >= ex_improved_uncanny_dodge_class_level[9]) and bit.band(stateValue, 0x29) == 0 then
				uncannyDodgeLevel = IEex_GetActorStat(targetID, 96) + IEex_GetActorStat(targetID, 104)
			end
			if bit.band(savingthrow, 0x880000) > 0 and (canSneakAttackOnEveryHit or canSneakAttackOnNextHit or IEex_IsValidBackstabDirection(sourceID, targetID) or bit.band(stateValue, 0x80140029) ~= 0 or isSleeping or IEex_GetActorSpellState(targetID, 183) or IEex_GetActorSpellState(targetID, 186)) and not isImmuneToSneakAttack and (bit.band(savingthrow, 0x60000) > 0 or bit.band(savingthrow, 0x800000) > 0 or (bit.band(savingthrow, 0x60000) == 0 and canSneakAttackWithSpells)) then
				if (uncannyDodgeLevel > 0 and rogueLevel < uncannyDodgeLevel + 4) then
					IEex_ApplyEffectToActor(targetID, {
	["opcode"] = 139,
	["target"] = 2,
	["timing"] = 1,
	["parameter1"] = ex_tra_55393,
	["parent_resource"] = parent_resource,
	["source_target"] = targetID,
	["source_id"] = sourceID
	})
				else
					isSneakAttack = true
					if canSneakAttackOnNextHit then
						if IEex_IsValidBackstabDirection(sourceID, targetID) then
							isTrueBackstab = true
						end
						IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 0,
["resource"] = "USINVSNA",
["parent_resource"] = "USINVSNR",
["source_id"] = sourceID
})
					end
					if not canSneakAttackOnEveryHit and not ex_no_sneak_attack_delay then
						IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = ex_sneak_attack_delay,
["parameter2"] = 216,
["parameter3"] = 1,
["parent_resource"] = "USSNEAKN",
["source_id"] = targetID
})

					end
					sneakAttackDiceNumber = math.floor((rogueLevel + 1) / 2)
					local improvedSneakAttackFeatID = ex_feat_name_id["ME_IMPROVED_SNEAK_ATTACK"]
					local improvedSneakAttackCount = 0
					if improvedSneakAttackFeatID ~= nil then
						improvedSneakAttackCount = IEex_ReadByte(sourceData + 0x744 + improvedSneakAttackFeatID, 0x0)
						sneakAttackDiceNumber = sneakAttackDiceNumber + improvedSneakAttackCount
					end
					IEex_IterateActorEffects(sourceID, function(eData)
						local theopcode = IEex_ReadDword(eData + 0x10)
						local theparameter2 = IEex_ReadDword(eData + 0x20)
						if theopcode == 288 and theparameter2 == 192 then
							local theparameter1 = IEex_ReadDword(eData + 0x1C)
							local thesavingthrow = IEex_ReadDword(eData + 0x40)
							local theresource = IEex_ReadLString(eData + 0x30, 8)
							local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
							if (bit.band(thesavingthrow, 0x10000) == 0 or theresource == parent_resource or theparent_resource == parent_resource or (launcherRES ~= "" and theparent_resource == launcherRES and bit.band(savingthrow, 0x1000000) > 0)) and (bit.band(thesavingthrow, 0x20000) == 0 or isTrueBackstab) and (bit.band(thesavingthrow, 0x40000) > 0 or rogueLevel > 0) then
								sneakAttackDiceNumber = sneakAttackDiceNumber + theparameter1
							end
						end
					end)
				end
			end
		end
	end
	local luck = 0
	local currentRoll = 0
	if IEex_IsSprite(sourceID, true) and (bit.band(savingthrow, 0x20000) > 0 or bit.band(savingthrow, 0x40000) > 0) then
		damage = damage + IEex_GetActorStat(sourceID, 50)
		luck = IEex_GetActorStat(sourceID, 32)
		if IEex_GetActorSpellState(sourceID, 64) then
			luck = 127
		end

		if IEex_GetActorStat(sourceID, 103) > 0 then
--			local favoredEnemyDamage = math.floor((IEex_GetActorStat(sourceID, 103) / 5) + 1)
			local favoredEnemyDamage = 4
			local enemyRace = IEex_ReadByte(creatureData + 0x26, 0x0)
			if enemyRace == IEex_ReadByte(sourceData + 0x7F7, 0x0) or enemyRace == IEex_ReadByte(sourceData + 0x7F8, 0x0) or enemyRace == IEex_ReadByte(sourceData + 0x7F9, 0x0) or enemyRace == IEex_ReadByte(sourceData + 0x7FA, 0x0) or enemyRace == IEex_ReadByte(sourceData + 0x7FB, 0x0) or enemyRace == IEex_ReadByte(sourceData + 0x7FC, 0x0) or enemyRace == IEex_ReadByte(sourceData + 0x7FD, 0x0) or enemyRace == IEex_ReadByte(sourceData + 0x7FE, 0x0) then
				damage = damage + favoredEnemyDamage
			end
		end
	elseif IEex_IsSprite(sourceID, true) and bit.band(savingthrow, 0x800000) > 0 and bit.band(internalFlags, 0x3000) == 0 then
		luck = IEex_GetActorStat(sourceID, 32)
		if IEex_GetActorSpellState(sourceID, 64) then
			luck = 127
		end
	else
		if IEex_GetActorStat(targetID, 32) ~= 0 then
			luck = 0 - IEex_GetActorStat(targetID, 32)
		end
		if IEex_IsSprite(sourceID, true) and IEex_GetActorSpellState(sourceID, 238) then
			local maximumMaximizeSpellLevel = 0
			IEex_IterateActorEffects(sourceID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				if theopcode == 288 and theparameter2 == 238 then
					local theparameter1 = IEex_ReadDword(eData + 0x1C)
					local theresource = IEex_ReadLString(eData + 0x30, 8)
					if theresource ~= "" and theresource == sourceSpell then
						maximumMaximizeSpellLevel = 99
					else
						maximumMaximizeSpellLevel = maximumMaximizeSpellLevel + theparameter1
					end
				end
			end)
			if (maximumMaximizeSpellLevel >= 99 or classSpellLevel > 0) and maximumMaximizeSpellLevel >= classSpellLevel then
				luck = 127
			end
		end
	end
	if bit.band(internalFlags, 0x200000) > 0 then
		luck = 127
	end
	if dicesize > 0 and dicenumber > 0 and (bit.band(savingthrow, 0x1000000) == 0 or (isSneakAttack and rogueLevel > 0)) then
		for i = 1, dicenumber, 1 do
			currentRoll = math.random(dicesize)
			if luck > 0 and currentRoll <= luck then
				currentRoll = luck + 1
			elseif luck < 0 and currentRoll > (dicesize + luck) then
				currentRoll = dicesize + luck
			end
			if currentRoll > dicesize then
				currentRoll = dicesize
			elseif currentRoll < 1 then
				currentRoll = 1
			end
			damage = damage + currentRoll
		end
	end
	local arterialStrikeCount = 0
	local hasCripplingStrikeFeat = false
	local isTouchAttackCriticalHit = (bit.band(internalFlags, 0x8000) > 0)
	if IEex_IsSprite(sourceID, true) then
		if bonusStat > 0 then
			local bonusStatValue = IEex_GetActorStat(sourceID, bonusStat)

			if bonusStat >= 36 and bonusStat <= 42 then
				bonusStatValue = math.floor((bonusStatValue - 10) / 2)
			end
			if bonusStatMultiplier ~= 0 then
				bonusStatValue = bonusStatValue * bonusStatMultiplier
			end
			if bonusStatDivisor ~= 0 then
				bonusStatValue = math.floor(bonusStatValue / bonusStatDivisor)
			end
			damage = damage + bonusStatValue
		end
		local saveBonusStatValue = 0
		if saveBonusStat > 0 and bit.band(savingthrow, 0x2000000) == 0 then
			if saveBonusStat == 120 or ex_source_spell[parent_resource] ~= nil then
				if casterClass == 11 then
					saveBonusStat = 38
				elseif casterClass == 3 or casterClass == 4 or casterClass == 7 or casterClass == 8 then
					saveBonusStat = 39
				elseif casterClass == 2 or casterClass == 10 then
					saveBonusStat = 42
				else
					local highestStatValue = IEex_GetActorStat(sourceID, 38)
					saveBonusStat = 38
					if IEex_GetActorStat(sourceID, 39) > highestStatValue then
						highestStatValue = IEex_GetActorStat(sourceID, 39)
						saveBonusStat = 39
					end
					if IEex_GetActorStat(sourceID, 42) > highestStatValue then
						highestStatValue = IEex_GetActorStat(sourceID, 42)
						saveBonusStat = 42
					end
				end
				saveBonusStatValue = IEex_GetActorStat(sourceID, saveBonusStat)
			else
				saveBonusStatValue = IEex_GetActorStat(sourceID, saveBonusStat)
			end
			if saveBonusStat >= 36 and saveBonusStat <= 42 then
				saveBonusStatValue = math.floor((saveBonusStatValue - 10) / 2)
			end
			if bonusStatMultiplier ~= 0 then
				saveBonusStatValue = saveBonusStatValue * bonusStatMultiplier
			end
			if bonusStatDivisor ~= 0 then
				saveBonusStatValue = math.floor(saveBonusStatValue / bonusStatDivisor)
			end
			savebonus = savebonus + saveBonusStatValue
		end
		if isTouchAttackCriticalHit then
			local criticalMultiplier = 2
			IEex_IterateActorEffects(sourceID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				if theopcode == 288 and theparameter2 == 195 and bit.band(thesavingthrow, 0x10000) == 0 then
					local theparameter1 = IEex_ReadDword(eData + 0x1C)
					criticalMultiplier = criticalMultiplier + theparameter1
				end
			end)
			damage = damage * criticalMultiplier
		end
		if bit.band(internalFlags, 0x100000) > 0 then
			damage = math.floor(damage * 1.5)
		end
		hasCripplingStrikeFeat = (bit.band(IEex_ReadDword(sourceData + 0x75C), 0x800) > 0)
		if bit.band(savingthrow, 0x880000) > 0 and isSneakAttack and sneakAttackDiceNumber > 0 then

			if IEex_GetActorSpellState(sourceID, 86) then
				if rogueLevel > 30 then
					arterialStrikeCount = 5
				elseif ex_arterial_strike[rogueLevel] ~= nil then
					arterialStrikeCount = ex_arterial_strike[rogueLevel]
				end
				sneakAttackDiceNumber = sneakAttackDiceNumber - arterialStrikeCount
			end
			if IEex_GetActorSpellState(sourceID, 87) then
				sneakAttackDiceNumber = sneakAttackDiceNumber - 2
			end
			dicesize = 6
			for i = 1, sneakAttackDiceNumber, 1 do
				currentRoll = math.random(dicesize)
				if luck > 0 and currentRoll <= luck then
					currentRoll = luck + 1
				elseif luck < 0 and currentRoll > (dicesize + luck) then
					currentRoll = dicesize + luck
				end
				if currentRoll > dicesize then
					currentRoll = dicesize
				elseif currentRoll < 1 then
					currentRoll = 1
				end
				damage = damage + currentRoll
			end
			local sneakAttackString = 25053
			if hasCripplingStrikeFeat then
				if rogueLevel > 30 then
					sneakAttackString = ex_crippling_strike[30]
				elseif rogueLevel > 0 then
					sneakAttackString = ex_crippling_strike[rogueLevel]
				end
			end
			local assassinFeatID = ex_feat_name_id["ME_ASSASSIN"]
			if assassinFeatID ~= nil and IEex_ReadByte(sourceData + 0x744 + assassinFeatID, 0x0) > 0 then
				sneakAttackString = ex_tra_929
				if hasCripplingStrikeFeat then
					if rogueLevel > 30 then
						sneakAttackString = ex_crippling_strike_assassin[30]
					elseif rogueLevel > 0 then
						sneakAttackString = ex_crippling_strike_assassin[rogueLevel]
					end
				end
			end
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = sneakAttackString,
["parent_resource"] = "USSNEAKM",
["source_id"] = sourceID
})
		end
	end
	if parameter2 ~= 0x7FFFFFFF and trueschool > 0 then
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 236 and bit.band(thesavingthrow, 0x10000) == 0 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				local thespecial = IEex_ReadDword(eData + 0x48)
				if (bit.band(thesavingthrow, 0x40000) == 0 or IEex_CompareActorAllegiances(sourceID, targetID) == 1) and (bit.band(thesavingthrow, 0x100000) == 0 or casterDomain == 0) then
					if (theresource == "" or theresource == sourceSpell) and (thespecial == trueschool or thespecial <= 0 or ((thespecial == 4 or thespecial == 5) and bit.band(savingthrow, 0x40) > 0) or ((thespecial == 2 or thespecial == 6) and bit.band(savingthrow, 0x80) > 0) or ((thespecial == 3 or thespecial == 7) and bit.band(savingthrow, 0x100) > 0) or ((thespecial == 1 or thespecial == 8) and bit.band(savingthrow, 0x200) > 0)) then
						savebonus = savebonus + theparameter1
						if bit.band(thesavingthrow, 0x80000) > 0 then
							damage = math.floor(damage / 2)
							if bit.band(parameter2, 0x3) == 0x3 then
								parameter2 = bit.band(parameter2, 0xFFFFFFFC)
							end
						end
					end
				end
			end
		end)
	end
	local isImmuneToDisease = false
	local isImmuneToPoison = false
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 288 and theparameter2 == 236 and bit.band(thesavingthrow, 0x10000) > 0 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if (bit.band(thesavingthrow, 0x40000) == 0 or IEex_CompareActorAllegiances(sourceID, targetID) == 1) and (bit.band(thesavingthrow, 0x100000) == 0 or casterDomain == 0) then
				if (theresource == "" or theresource == sourceSpell) and (thespecial == trueschool or thespecial <= 0 or ((thespecial == 4 or thespecial == 5) and bit.band(savingthrow, 0x40) > 0) or ((thespecial == 2 or thespecial == 6) and bit.band(savingthrow, 0x80) > 0) or ((thespecial == 3 or thespecial == 7) and bit.band(savingthrow, 0x100) > 0) or ((thespecial == 1 or thespecial == 8) and bit.band(savingthrow, 0x200) > 0)) then
					savebonus = savebonus + theparameter1
					if bit.band(thesavingthrow, 0x80000) > 0 then
						damage = math.floor(damage / 2)
						if bit.band(parameter2, 0x3) == 0x3 then
							parameter2 = bit.band(parameter2, 0xFFFFFFFC)
						end
					end
				end
			end
		elseif theopcode == 101 and theparameter2 == 25 then
			isImmuneToPoison = true
		elseif theopcode == 101 and theparameter2 == 78 then
			isImmuneToDisease = true
		end
	end)
	if IEex_GetActorStat(targetID, 99) >= 9 or IEex_GetActorStat(targetID, 101) >= 11 then
		isImmuneToPoison = true
	end
	if IEex_GetActorStat(targetID, 101) >= 5 or IEex_GetActorStat(targetID, 102) >= 1 then
		isImmuneToDisease = true
	end
	local newSavingThrow = 0
	local newParameter3 = bit.band(savingthrow, 0x78000000)
	if bit.band(savingthrow, 0x400) > 0 then
		newSavingThrow = bit.bor(newSavingThrow, 0x4)
	end
	if bit.band(savingthrow, 0x800) > 0 then
		newSavingThrow = bit.bor(newSavingThrow, 0x8)
	end
	if bit.band(savingthrow, 0x1000) > 0 then
		newSavingThrow = bit.bor(newSavingThrow, 0x10)
	end
	local damageBlocked = false
	local damageAbsorbed = false
--	if IEex_GetActorSpellState(targetID, 214) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 214 and (theparameter1 == IEex_ReadWord(effectData + 0x1E, 0x0) or (theresource == parent_resource and theresource ~= "")) and (bit.band(thesavingthrow, 0x20000) == 0 or bit.band(thesavingthrow, 0x78000000) == bit.band(newParameter3, 0x78000000)) then
				damageBlocked = true
				if bit.band(thesavingthrow, 0x10000) > 0 then
					damageAbsorbed = true
				end
			end
		end)
--	end
	if IEex_IsSprite(sourceID, true) and bit.band(savingthrow, 0x10000) > 0 then
		newParameter3 = bit.bor(newParameter3, 0x40000)
		local damageMultiplier = 100
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 73 and theparameter2 > 0 then
				if ex_damage_multiplier_type[damageType] == theparameter2 then
					local thesavingthrow = IEex_ReadDword(eData + 0x40)
					local thespecial = IEex_ReadDword(eData + 0x48)
					damageMultiplier = damageMultiplier + theparameter1
					local theresource = IEex_ReadLString(eData + 0x30, 8)
					if (theresource == "" or theresource == parent_resource) and (bit.band(thesavingthrow, 0x20000) == 0 or bit.band(thesavingthrow, 0x78000000) == bit.band(newParameter3, 0x78000000)) then
						if bit.band(thesavingthrow, 0x100000) == 0 then
							damageMultiplier = damageMultiplier + thespecial
						else
							damage = damage + thespecial
						end
					end
				end
			elseif parameter2 == 0x7FFFFFFF and theopcode == 288 and theparameter2 == 191 then
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				local thespecial = IEex_ReadDword(eData + 0x48)
				if bit.band(thesavingthrow, 0x7000000) == 0x1000000 then
					if thespecial == 0 then
						damage = damage + theparameter1
					elseif thespecial == 2 then
						damageMultiplier = damageMultiplier + theparameter1
					end
				end
			end
		end)
		damage = math.floor(damage * damageMultiplier / 100)
	end
	local general = IEex_ReadByte(creatureData + 0x25, 0x0)
	if parameter2 == 0x7FFFFFFF and general == 4 then
		parameter2 = 0x400000
		savingthrow = bit.bor(savingthrow, 0x8000000)
	elseif parameter2 == 0x400000 and bit.band(savingthrow, 0x10000000) > 0 then
		if general == 4 then
			parameter2 = 0x7FFFFFFF
		elseif IEex_GetActorSpellState(targetID, 109) then
			return
		end
	end
	if parameter4 > 0 then
		damage = damage * parameter4
		newParameter3 = bit.bor(newParameter3, 0x10000)
	end
	if bit.band(savingthrow, 0x2000000) > 0 then
		local weaponEnchantment = IEex_ReadByte(effectData + 0x47, 0x0)
		local damageReduction = IEex_ReadByte(creatureData + 0x758, 0x0)
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			if theopcode == 436 then
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				if theparameter2 > damageReduction then
					damageReduction = theparameter2
				end
			end
		end)
		if IEex_GetActorSpellState(targetID, 18) and weaponEnchantment < 5 and damageReduction < 5 then
			damage = damage - 10
		elseif weaponEnchantment < damageReduction then
			damage = damage - damageReduction
		end
	end
	local newvvcresource = ""
	local newparent_resource = parent_resource
	if bit.band(savingthrow, 0x20000) > 0 then
		newvvcresource = parent_resource
		newparent_resource = "IEEX_DAM"
	end
	local previousMirrorImages = 0
	if ((parameter2 == 0x200000 or parameter2 == 0x200003) and isImmuneToPoison) or ((parameter2 == 0x40000000 or parameter2 == 0x40000003) and isImmuneToDisease) then
		damage = 0
	end
	if damage <= 0 then
		damage = 0
	else
		if parameter2 == 0x7FFFFFFF or damageAbsorbed then
			newSavingThrow = bit.band(newSavingThrow, 0xFFFFE3E3)
			IEex_ApplyEffectToActor(targetID, {
	["opcode"] = 17,
	["target"] = 2,
	["timing"] = 1,
	["parameter1"] = damage,
	["parameter2"] = 0,
	["savingthrow"] = newSavingThrow,
	["savebonus"] = savebonus,
	["vvcresource"] = newvvcresource,
	["parent_resource"] = newparent_resource,
	["source_target"] = targetID,
	["source_id"] = sourceID
	})
		elseif damageBlocked == false then
			if bit.band(savingthrow, 0x4000000) > 0 then
				previousMirrorImages = IEex_ReadSignedByte(creatureData + 0xA60, 0x0)
				IEex_WriteByte(creatureData + 0xA60, 0)
				IEex_WriteByte(creatureData + 0x18B8, 0)
				IEex_WriteDword(creatureData + 0x920, bit.band(IEex_ReadDword(creatureData + 0x920), 0xBFFFFFFF))
				IEex_WriteDword(creatureData + 0x1778, bit.band(IEex_ReadDword(creatureData + 0x1778), 0xBFFFFFFF))
			end
			IEex_ApplyEffectToActor(targetID, {
	["opcode"] = 12,
	["target"] = 2,
	["timing"] = 1,
	["parameter1"] = damage,
	["parameter2"] = parameter2,
	["parameter3"] = newParameter3,
	["savingthrow"] = newSavingThrow,
	["savebonus"] = savebonus,
	["vvcresource"] = newvvcresource,
	["parent_resource"] = newparent_resource,
	["source_target"] = targetID,
	["source_id"] = sourceID
	})
			if previousMirrorImages > 0 then
				IEex_WriteByte(creatureData + 0xA60, previousMirrorImages)
				IEex_WriteByte(creatureData + 0x18B8, previousMirrorImages)
				IEex_WriteDword(creatureData + 0x920, bit.bor(IEex_ReadDword(creatureData + 0x920), 0x40000000))
				IEex_WriteDword(creatureData + 0x1778, bit.bor(IEex_ReadDword(creatureData + 0x1778), 0x40000000))
			end
		end
		if (bit.band(savingthrow, 0x200000) > 0 or bit.band(savingthrow, 0x400000) > 0) and damageBlocked == false then
			local targetResistance = 0
			if ex_damage_resistance_stat[damageType] ~= nil then
				targetResistance = IEex_GetActorStat(targetID, ex_damage_resistance_stat[damageType])
			end
			local damageDrained = damage - targetResistance
			local drainDuration = 350
			if parameter3 > 0 then
				drainDuration = parameter3
			end
			if damageDrained > 0 then
				IEex_ApplyEffectToActor(targetID, {
	["opcode"] = 139,
	["target"] = 2,
	["timing"] = 1,
	["parameter1"] = 4392,
	["savingthrow"] = newSavingThrow,
	["savebonus"] = savebonus,
	["parent_resource"] = parent_resource,
	["source_target"] = targetID,
	["source_id"] = sourceID
	})
				if sourceID > 0 then
					if bit.band(savingthrow, 0x200000) > 0 then
						IEex_ApplyEffectToActor(sourceID, {
	["opcode"] = 18,
	["target"] = 2,
	["timing"] = 0,
	["duration"] = drainDuration,
	["parameter1"] = damageDrained,
	["parameter2"] = 3,
	["parent_resource"] = parent_resource,
	["source_target"] = sourceID,
	["source_id"] = sourceID
	})
					end
					IEex_ApplyEffectToActor(sourceID, {
	["opcode"] = 17,
	["target"] = 2,
	["timing"] = 1,
	["parameter1"] = damageDrained,
	["parent_resource"] = parent_resource,
	["source_target"] = sourceID,
	["source_id"] = sourceID
	})
				end
			end
		end
	end
	if IEex_IsSprite(sourceID, true) and isSneakAttack then
		if IEex_GetActorSpellState(sourceID, 86) then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 37673,
["parent_resource"] = "USSNEAKM",
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = "USWOUN0" .. arterialStrikeCount,
["parent_resource"] = "USWOUN0" .. arterialStrikeCount,
["source_id"] = sourceID
})
		end
		if IEex_GetActorSpellState(sourceID, 87) then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 37675,
["parent_resource"] = "USSNEAKM",
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 176,
["target"] = 2,
["timing"] = 0,
["duration"] = 70,
["parameter1"] = 50,
["parameter2"] = 2,
["parent_resource"] = "USHAMSTR",
["source_id"] = sourceID
})
		end
		if hasCripplingStrikeFeat then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 44,
["target"] = 2,
["timing"] = 0,
["duration"] = 70,
["parameter1"] = math.floor(rogueLevel / 3) * -1,
["parent_resource"] = "USCRPSTR",
["source_id"] = sourceID
})
		end
--		if IEex_GetActorSpellState(sourceID, 223) then
			local onSneakAttackEffectList = {}
			IEex_IterateActorEffects(sourceID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				if theopcode == 288 and theparameter2 == 223 then
	--				local theparameter1 = IEex_ReadDword(eData + 0x1C)
	--				local matchHeader = IEex_ReadByte(eData + 0x48, 0x0)
					local thesavingthrow = IEex_ReadDword(eData + 0x40)
					local spellRES = IEex_ReadLString(eData + 0x30, 8)
					if spellRES ~= "" then
						local newEffectTarget = targetID
						local newEffectTargetX = IEex_ReadDword(effectData + 0x84)
						local newEffectTargetY = IEex_ReadDword(effectData + 0x88)
						if (bit.band(thesavingthrow, 0x200000) > 0) then
							newEffectTarget = sourceID
							newEffectTargetX = IEex_ReadDword(effectData + 0x7C)
							newEffectTargetY = IEex_ReadDword(effectData + 0x80)
						end
						local newEffectSource = sourceID
						local newEffectSourceX = IEex_ReadDword(effectData + 0x7C)
						local newEffectSourceY = IEex_ReadDword(effectData + 0x80)
						if (bit.band(thesavingthrow, 0x400000) > 0) then
							newEffectSource = targetID
							newEffectSourceX = IEex_ReadDword(effectData + 0x84)
							newEffectSourceY = IEex_ReadDword(effectData + 0x88)
						end
						local usesLeft = IEex_ReadByte(eData + 0x49, 0x0)
						if usesLeft == 1 then
							local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
							IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = theparent_resource,
["source_id"] = sourceID
})
						elseif usesLeft > 0 then
							usesLeft = usesLeft - 1
							IEex_WriteByte(eData + 0x49, usesLeft)
						end
						local sneakAttackCasterLevel = casterlvl
						if bit.band(thesavingthrow, 0x1000000) > 0 then
							sneakAttackCasterLevel = IEex_GetActorStat(sourceID, 104)
							if sneakAttackCasterLevel == 0 then
								sneakAttackCasterLevel = 1
							end
						end
						table.insert(onSneakAttackEffectList, {spellRES, sneakAttackCasterLevel, newEffectTarget, newEffectSource, newEffectTargetX, newEffectTargetY, newEffectSourceX, newEffectSourceY})
					end
				end
			end)
			for k, v in ipairs(onSneakAttackEffectList) do
				IEex_ApplyEffectToActor(v[3], {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = v[1],
["source_x"] = v[7],
["source_y"] = v[8],
["target_x"] = v[5],
["target_y"] = v[6],
["casterlvl"] = v[2],
["parent_resource"] = v[1],
["source_target"] = v[3],
["source_id"] = v[4]
})
			end
--		end
	end
end


function MESNEAKA(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local damage = 0
	local dicesize = 6
	local dicenumber = math.floor((IEex_GetActorStat(sourceID, 104) + 1) / 2)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local luck = 0
	if bit.band(savingthrow, 0x20000) > 0 or bit.band(savingthrow, 0x40000) > 0 then
		damage = damage + IEex_GetActorStat(sourceID, 50)
		luck = IEex_GetActorStat(sourceID, 32)
		if IEex_GetActorSpellState(sourceID, 64) then
			luck = 127
		end
		parent_resource = ""
	else
		if IEex_GetActorStat(targetID, 32) ~= 0 then
			luck = 0 - IEex_GetActorStat(targetID, 32)
		end
	end
	if dicesize > 0 then
		for i = 1, dicenumber, 1 do
			local currentRoll = math.random(dicesize)
			if luck > 0 and currentRoll <= luck then
				currentRoll = luck + 1
			elseif luck < 0 and currentRoll > (dicesize + luck) then
				currentRoll = dicesize + luck
			end
			if currentRoll > dicesize then
				currentRoll = dicesize
			elseif currentRoll < 1 then
				currentRoll = 1
			end
			damage = damage + currentRoll
		end
	end
	if bit.band(savingthrow, 0x10000) > 0 then
		local damageMultiplier = 100
		local damageType = bit.band(parameter2, 0xFFFF0000)
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 73 and theparameter2 > 0 then
				if ex_damage_multiplier_type[damageType] == theparameter2 then
					local theparameter1 = IEex_ReadDword(eData + 0x1C)
					damageMultiplier = damageMultiplier + theparameter1
				end
			end
		end)
		damage = math.floor(damage * damageMultiplier / 100)
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 12,
["target"] = 2,
["timing"] = 1,
["parameter1"] = damage,
["parameter2"] = parameter2,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
end

function MEHEALIN(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceData = 0
	local healing = IEex_ReadSignedWord(effectData + 0x18, 0x0)
	local dicesize = IEex_ReadByte(effectData + 0x1A, 0x0)
	local dicenumber = IEex_ReadByte(effectData + 0x1B, 0x0)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local parameter3 = IEex_ReadDword(effectData + 0x5C)
	local damageType = bit.band(parameter2, 0xFFFF0000)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if IEex_IsSprite(sourceID, true) then
		sourceData = IEex_GetActorShare(sourceID)
		if IEex_GetActorSpellState(sourceID, 238) and dicenumber > 0 then
			local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
			local sourceSpell = ex_source_spell[parent_resource]
			if sourceSpell == nil then
				sourceSpell = parent_resource
			end
			local classSpellLevel = IEex_GetClassSpellLevel(sourceID, casterClass, sourceSpell)
			local maximumMaximizeSpellLevel = 0
			IEex_IterateActorEffects(sourceID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				if theopcode == 288 and theparameter2 == 238 then
					local theparameter1 = IEex_ReadDword(eData + 0x1C)
					local theresource = IEex_ReadLString(eData + 0x30, 8)
					if theresource ~= "" and theresource == sourceSpell then
						maximumMaximizeSpellLevel = 99
					else
						maximumMaximizeSpellLevel = maximumMaximizeSpellLevel + theparameter1
					end
				end
			end)
			if ((maximumMaximizeSpellLevel >= 99 or classSpellLevel > 0) and maximumMaximizeSpellLevel > classSpellLevel) or bit.band(internalFlags, 0x200000) > 0 then
				healing = healing + dicesize * dicenumber
				dicenumber = 0
				dicesize = 0
			end
		end
		if parameter2 == 3 then
			local charismaModifier = ((IEex_GetActorStat(sourceID, 42) - 10) / 2)
			if charismaModifier < 1 then
				charismaModifier = 1
			end
			healing = charismaModifier * IEex_GetActorStat(sourceID, 102)
			parameter2 = 0
		elseif parameter2 == 4 then
			local wisdomModifier = ((IEex_GetActorStat(sourceID, 39) - 10) / 2)
			if wisdomModifier < 1 then
				wisdomModifier = 1
			end
			healing = wisdomModifier * IEex_GetActorStat(sourceID, 101)
			parameter2 = 0
		elseif parameter2 == 5 then
			healing = IEex_GetActorStat(sourceID, 98) * 2
			parameter2 = 0
		end
--		if IEex_GetActorSpellState(sourceID, 191) then
			local healingMultiplier = 100
			IEex_IterateActorEffects(sourceID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				if theopcode == 288 and theparameter2 == 191 then
					local theparameter1 = IEex_ReadDword(eData + 0x1C)
					local thesavingthrow = IEex_ReadDword(eData + 0x40)
					local thespecial = IEex_ReadDword(eData + 0x48)
					if (bit.band(thesavingthrow, 0x100000) == 0 or targetID ~= sourceID) and bit.band(thesavingthrow, 0x7000000) == bit.band(savingthrow, 0x7000000) then
						if thespecial == 0 then
							healing = healing + theparameter1
						elseif thespecial == 2 then
							healingMultiplier = healingMultiplier + theparameter1
						end
					end
				end
			end)
			healing = math.floor(healing * healingMultiplier / 100)
			dicenumber = math.floor(dicenumber * healingMultiplier / 100)
--		end
	end
	if bit.band(internalFlags, 0x100000) > 0 then
		healing = math.floor(healing * 1.5)
		dicenumber = math.floor(dicenumber * 1.5)
	end
	if IEex_ReadByte(creatureData + 0x25, 0x0) == 4 and bit.band(savingthrow, 0x1000000) > 0 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 1,
["parameter1"] = healing + dicesize * 0x100 + dicenumber * 0x10000,
["parameter2"] = 0x400000,
["savingthrow"] = 0x8010000,
["resource"] = "EXDAMAGE",
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
	else
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 17,
["target"] = 2,
["timing"] = 1,
["parameter1"] = healing,
["parameter2"] = parameter2,
["dicenumber"] = dicenumber,
["dicesize"] = dicesize,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
	end
end

function MESETGLB(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local variableName = IEex_ReadLString(effectData + 0x18, 8)
	local value = IEex_ReadDword(effectData + 0x44)
	IEex_SetGlobal(variableName, value)
end

ex_feat_bit_location = {
[0x774] = {0x760, 0x80},
[0x775] = {0x760, 0x200000},
[0x776] = {0x760, 0x800000},
[0x777] = {0x760, 0x40},
[0x778] = {0x760, 0x400000},
[0x779] = {0x760, 0x100},
[0x77A] = {0x760, 0x1000},
[0x77B] = {0x760, 0x400},
[0x77C] = {0x760, 0x1000000},
[0x77D] = {0x760, 0x200},
[0x77E] = {0x760, 0x800},
[0x77F] = {0x760, 0x2000000},
[0x780] = {0x764, 0x20},
[0x781] = {0x75C, 0x10},
[0x782] = {0x75C, 0x100},
[0x783] = {0x75C, 0x8},
[0x784] = {0x760, 0x10000000},
[0x785] = {0x760, 0x20000000},
[0x786] = {0x760, 0x40000000},
[0x787] = {0x760, 0x80000000},
[0x788] = {0x764, 0x1},
[0x78D] = {0x75C, 0x40000},
}

ex_feat_location = {
[3] = {0x783, 3},
[4] = {0x781, 3},
[8] = {0x782, 2},
[18] = {0x78D, 3},
[20] = {0x789, 3},
[21] = {0x78A, 3},
[22] = {0x78B, 3},
[23] = {0x78C, 3},
[38] = {0x777, 3},
[39] = {0x774, 3},
[40] = {0x779, 3},
[41] = {0x77D, 3},
[42] = {0x77B, 3},
[43] = {0x77E, 3},
[44] = {0x77A, 3},
[53] = {0x775, 3},
[54] = {0x778, 3},
[55] = {0x776, 3},
[56] = {0x77C, 3},
[57] = {0x77F, 3},
[60] = {0x784, 2},
[61] = {0x785, 2},
[62] = {0x786, 2},
[63] = {0x787, 2},
[64] = {0x788, 2},
[69] = {0x780, 5},
}

function MEMODFEA(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local featID = IEex_ReadDword(effectData + 0x44)
	local featBitLocation = 0x75C + math.floor(featID / 32) * 0x4
	local featBits = IEex_ReadDword(creatureData + featBitLocation)
	local featBit = 2 ^ (featID % 32)
	local featValue = 0
	local featMax = 1
	if ex_feat_location[featID] ~= nil then
		featValue = IEex_ReadByte(creatureData + ex_feat_location[featID][1], 0x0)
		featMax = ex_feat_location[featID][2]
	elseif featID <= 74 then
		if bit.band(featBits, featBit) > 0 then
			featValue = 1
		end
	else
		featValue = IEex_ReadByte(creatureData + 0x744 + featID, 0x0)
		featMax = tonumber(IEex_2DAGetAtRelated("B3FEATS", "ID", "MAX", function(id) return tonumber(id) == featID end))
	end
	if featID == 4 and bit.band(IEex_ReadDword(creatureData + 0x740), 0x1000) > 0 then
		parameter1 = parameter1 * ex_armored_arcana_multiplier
		featMax = featMax * ex_armored_arcana_multiplier
	end
	featValue = featValue + parameter1
	if featValue <= 0 then
		featValue = 0
		IEex_WriteDword(creatureData + featBitLocation, bit.band(featBits, 0xFFFFFFFF - featBit))
	else
		IEex_WriteDword(creatureData + featBitLocation, bit.bor(featBits, featBit))
		if featValue > featMax and bit.band(savingthrow, 0x10000) == 0 then
			featValue = featMax
		end
	end
	if ex_feat_location[featID] ~= nil then
		IEex_WriteByte(creatureData + ex_feat_location[featID][1], featValue)
	elseif featID >= 75 then
		IEex_WriteByte(creatureData + 0x744 + featID, featValue)
	end
end

function MEMODOFF(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local special = IEex_ReadWord(effectData + 0x44, 0x0)
	local readSize = IEex_ReadWord(effectData + 0x46, 0x0)
	if (parameter1 > 65535 or parameter1 < -65536) and readSize < 4 then
		readSize = 4
	elseif (parameter1 > 255 or parameter1 < -256) and readSize < 2 then
		readSize = 2
	elseif readSize < 1 then
		readSize = 1
	end
	if readSize == 1 then
		local value = IEex_ReadSignedByte(creatureData + special, 0x0)
		if parameter2 == 0 then
			value = value + parameter1
		elseif parameter2 == 1 then
			value = parameter1
		elseif parameter2 == 2 then
			value = math.floor(value * parameter1 / 100)
		end
		IEex_WriteByte(creatureData + special, value)
	elseif readSize == 2 then
		local value = IEex_ReadSignedWord(creatureData + special, 0x0)
		if parameter2 == 0 then
			value = value + parameter1
		elseif parameter2 == 1 then
			value = parameter1
		elseif parameter2 == 2 then
			value = math.floor(value * parameter1 / 100)
		end
		IEex_WriteWord(creatureData + special, value)
	elseif readSize == 4 then
		local value = IEex_ReadDword(creatureData + special)
		if parameter2 == 0 then
			value = value + parameter1
		elseif parameter2 == 1 then
			value = parameter1
		elseif parameter2 == 2 then
			value = math.floor(value * parameter1 / 100)
		end
		IEex_WriteDword(creatureData + special, value)
	else
	end
end

function MECRITIM(effectData, creatureData)
	local timing = IEex_ReadDword(effectData + 0x20)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if timing == 1 then
		local specialFlags = IEex_ReadByte(creatureData + 0x89F, 0x0)
		if bit.band(savingthrow, 0x10000) > 0 then
			IEex_WriteByte(creatureData + 0x70A, 0)
			IEex_WriteByte(creatureData + 0x89F, bit.band(specialFlags, 0xFD))
		else
			IEex_WriteByte(creatureData + 0x70A, 1)
			IEex_WriteByte(creatureData + 0x89F, bit.bor(specialFlags, 0x2))
		end
		IEex_WriteDword(effectData + 0x114, 1)
	else
		return
	end
end

function IEex_ApplyStatScaling(targetID)
	local creatureData = IEex_GetActorShare(targetID)
	local noncumulativeOpcodeFunctionsCalled = {}
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theresource = IEex_ReadLString(eData + 0x30, 8)

		if theopcode == 500 then
			if ex_noncumulative_opcode_functions[theresource] ~= nil and noncumulativeOpcodeFunctionsCalled[theresource] == nil then
				noncumulativeOpcodeFunctionsCalled[theresource] = true
				_G[theresource](eData + 0x4, creatureData, true)
			end
			if ex_stat_scaling_functions[theresource] ~= nil then
				_G[theresource](eData + 0x4, creatureData, true)
			end
		end

	end)
end

function IEex_ApplyStatSpell(targetID, index, statValue)
	if statValue < 0 then
		statValue = 0
	end
	local statSpellList = ex_stat_spells[index]
	if statSpellList ~= nil then
		local spellRES = ""
		local highest = -1
		for key,value in pairs(statSpellList) do
			if statValue >= key and key > highest then
				spellRES = value
				highest = key
			end
		end
		if spellRES ~= "" then
			IEex_ApplyResref(spellRES, targetID)
		end
	end
end

function MEOP16(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(targetID, false) then return end
	local hasImprovedHaste = false
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		if theopcode == 288 and theparameter2 == 138 then
			hasImprovedHaste = true
		end
	end)
	if hasImprovedHaste then return end
	local attacksPerRound = IEex_ReadSignedWord(creatureData + 0x93A, 0x0) + 1
	if attacksPerRound > 5 then
		attacksPerRound = 5
	end
	IEex_WriteWord(creatureData + 0x93A, attacksPerRound)
	IEex_WriteWord(creatureData + 0x92C, IEex_ReadSignedWord(creatureData + 0x92C, 0x0) + 4)
	IEex_WriteWord(creatureData + 0x93E, IEex_ReadSignedWord(creatureData + 0x93E, 0x0) + 2)
	IEex_WriteDword(creatureData + 0x920, bit.bor(IEex_ReadDword(creatureData + 0x920), 0x8000))
	local animationData = IEex_ReadDword(creatureData + 0x50F0)
	local movementRate = IEex_ReadByte(animationData + 0x7, 0x0) * 2
	if movementRate > 255 then
		movementRate = 255
	end
	IEex_WriteByte(animationData + 0x7, movementRate)
end

function MEOP40(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(targetID, false) then return end
	local attacksPerRound = IEex_ReadSignedWord(creatureData + 0x93A, 0x0) - 1
	if attacksPerRound < 1 then
		attacksPerRound = 1
	end
	IEex_WriteWord(creatureData + 0x93A, attacksPerRound)
	IEex_WriteWord(creatureData + 0x92C, IEex_ReadSignedWord(creatureData + 0x92C, 0x0) - 4)
	IEex_WriteWord(creatureData + 0x93E, IEex_ReadSignedWord(creatureData + 0x93E, 0x0) - 2)
	IEex_WriteDword(creatureData + 0x920, bit.bor(IEex_ReadDword(creatureData + 0x920), 0x10000))
	local animationData = IEex_ReadDword(creatureData + 0x50F0)
	local movementRate = math.floor(IEex_ReadByte(animationData + 0x7, 0x0) / 2)
	IEex_WriteByte(animationData + 0x7, movementRate)
end

function MEOP130(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(targetID, false) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	if parameter1 == 0 then
		parameter1 = 1
	end
	IEex_WriteWord(creatureData + 0x938, IEex_ReadSignedWord(creatureData + 0x938, 0x0) + parameter1)
	IEex_WriteWord(creatureData + 0x93C, IEex_ReadSignedWord(creatureData + 0x93C, 0x0) + parameter1)
	IEex_WriteWord(creatureData + 0x93E, IEex_ReadSignedWord(creatureData + 0x93E, 0x0) + parameter1)
	IEex_WriteWord(creatureData + 0x940, IEex_ReadSignedWord(creatureData + 0x940, 0x0) + parameter1)
	IEex_WriteDword(creatureData + 0x920, bit.bor(IEex_ReadDword(creatureData + 0x920), 0x800000))
end

function MEOP143(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = IEex_ReadDword(effectData + 0x10),
["power"] = IEex_ReadDword(effectData + 0x14),
["parameter1"] = IEex_ReadDword(effectData + 0x18),
["parameter2"] = IEex_ReadDword(effectData + 0x1C),
["timing"] = 0,
["duration"] = 0,
["resource"] = IEex_ReadLString(effectData + 0x6C, 8),
["dicenumber"] = IEex_ReadDword(effectData + 0x34),
["dicesize"] = IEex_ReadDword(effectData + 0x38),
["savingthrow"] = IEex_ReadDword(effectData + 0x3C),
["savebonus"] = IEex_ReadDword(effectData + 0x40),
["special"] = IEex_ReadDword(effectData + 0x44),
["school"] = IEex_ReadDword(effectData + 0x48),
["resist_dispel"] = IEex_ReadDword(effectData + 0x58),
["parameter3"] = IEex_ReadDword(effectData + 0x5C),
["parameter4"] = IEex_ReadDword(effectData + 0x60),
["parameter5"] = IEex_ReadDword(effectData + 0x64),
["resource2"] = IEex_ReadLString(effectData + 0x74, 8),
["source_x"] = IEex_ReadDword(effectData + 0x7C),
["source_y"] = IEex_ReadDword(effectData + 0x80),
["target_x"] = IEex_ReadDword(effectData + 0x84),
["target_y"] = IEex_ReadDword(effectData + 0x88),
["restype"] = IEex_ReadDword(effectData + 0x8C),
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["resource_flags"] = IEex_ReadDword(effectData + 0x98),
["impact_projectile"] = IEex_ReadDword(effectData + 0x9C),
["sourceslot"] = IEex_ReadDword(effectData + 0xA0),
["effvar"] = IEex_ReadLString(effectData + 0xA4, 32),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["sectype"] = IEex_ReadDword(effectData + 0x4C),
["source_target"] = sourceID,
["source_id"] = targetID
})
end

function MEOP408(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(targetID, false) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	if parameter1 == 0 then
		parameter1 = 4
	end
	IEex_WriteWord(creatureData + 0x9A6, IEex_ReadSignedWord(creatureData + 0x9A6, 0x0) + parameter1)
end

function MEOP409(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(targetID, false) or not IEex_IsSprite(sourceID, true) then return end
	local sourceData = IEex_GetActorShare(sourceID)
	local sourceAlignment = IEex_ReadByte(sourceData + 0x35, 0x0)
	local targetAlignment = IEex_ReadByte(creatureData + 0x35, 0x0)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	if parameter2 == 0 and sourceAlignment ~= targetAlignment then
		IEex_WriteWord(creatureData + 0x938, IEex_ReadSignedWord(creatureData + 0x938, 0x0) + parameter1)
		IEex_WriteWord(creatureData + 0x93C, IEex_ReadSignedWord(creatureData + 0x93C, 0x0) + parameter1)
		IEex_WriteWord(creatureData + 0x93E, IEex_ReadSignedWord(creatureData + 0x93E, 0x0) + parameter1)
		IEex_WriteWord(creatureData + 0x940, IEex_ReadSignedWord(creatureData + 0x940, 0x0) + parameter1)
		IEex_WriteWord(creatureData + 0x9A6, IEex_ReadSignedWord(creatureData + 0x9A6, 0x0) + parameter1)
	elseif parameter2 == 1 and sourceAlignment == targetAlignment then
		IEex_WriteWord(creatureData + 0x938, IEex_ReadSignedWord(creatureData + 0x938, 0x0) + parameter1)
		IEex_WriteWord(creatureData + 0x93C, IEex_ReadSignedWord(creatureData + 0x93C, 0x0) + parameter1)
		IEex_WriteWord(creatureData + 0x93E, IEex_ReadSignedWord(creatureData + 0x93E, 0x0) + parameter1)
		IEex_WriteWord(creatureData + 0x940, IEex_ReadSignedWord(creatureData + 0x940, 0x0) + parameter1)
		IEex_WriteWord(creatureData + 0x9A6, IEex_ReadSignedWord(creatureData + 0x9A6, 0x0) + parameter1)
		local attacksPerRound = IEex_ReadSignedWord(creatureData + 0x93A, 0x0) - 1
		if attacksPerRound < 1 then
			attacksPerRound = 1
		end
		IEex_WriteWord(creatureData + 0x93A, attacksPerRound)
	end
end

function MEOP415(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(targetID, false) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	if parameter1 == 0 then
		local casterLevel = IEex_ReadByte(effectData + 0xC4, 0x0)
		if casterLevel < 6 then
			parameter1 = 3
		elseif casterLevel < 12 then
			parameter1 = 4
		else
			parameter1 = 5
		end
	end
	IEex_WriteWord(creatureData + 0x92C, IEex_ReadSignedWord(creatureData + 0x92C, 0x0) + parameter1)
end

function MEOP427(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(targetID, false) then return end
	IEex_WriteWord(creatureData + 0x936, IEex_ReadSignedWord(creatureData + 0x936, 0x0) + 4)
	IEex_WriteWord(creatureData + 0x938, IEex_ReadSignedWord(creatureData + 0x938, 0x0) + 4)
end

function MEOP452(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(targetID, false) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	if parameter1 == 0 then
		parameter1 = 1
	end
	IEex_WriteWord(creatureData + 0x938, IEex_ReadSignedWord(creatureData + 0x938, 0x0) - parameter1)
	IEex_WriteWord(creatureData + 0x93C, IEex_ReadSignedWord(creatureData + 0x93C, 0x0) - parameter1)
	IEex_WriteWord(creatureData + 0x93E, IEex_ReadSignedWord(creatureData + 0x93E, 0x0) - parameter1)
	IEex_WriteWord(creatureData + 0x940, IEex_ReadSignedWord(creatureData + 0x940, 0x0) - parameter1)
end

function MEIMPALA(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(targetID, false) then return end
	local castingSpeed = IEex_ReadSignedWord(creatureData + 0x9E4, 0x0)
	if castingSpeed > 0 then
		IEex_WriteWord(creatureData + 0x9E4, 0)
	end
end

function MESTATSC(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local statValue = 0
	local stat = IEex_ReadWord(effectData + 0x18, 0x0)
	local otherStat = IEex_ReadByte(effectData + 0x1A, 0x0)
	local subtractStat = IEex_ReadByte(effectData + 0x1B, 0x0)
	local index = IEex_ReadWord(effectData + 0x1C, 0x0)
	local matchNonStat = IEex_ReadWord(effectData + 0x1E, 0x0)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local modifiedStat = IEex_ReadDword(effectData + 0x44)
	if bit.band(savingthrow, 0x200000) > 0 then
		local matchRace = IEex_ReadByte(effectData + 0x1E, 0x0)
		local matchSubrace = IEex_ReadByte(effectData + 0x1F, 0x0)
		if matchRace ~= IEex_ReadByte(creatureData + 0x26, 0x0) or (matchSubrace ~= 0 and matchSubrace ~= IEex_GetActorStat(targetID, 93) + 1) then return end
	end
	statValue = IEex_GetActorStat(targetID, stat)
	if otherStat > 0 then
		local otherStatValue = IEex_GetActorStat(targetID, otherStat)
		if otherStatValue > statValue then
			statValue = otherStatValue
		end
	end
	if statValue < 0 then
		statValue = 0
	end
	local statScalingList = ex_stat_scaling[index]
	if statScalingList ~= nil then
		local modificationAmount = 0
		local highest = -1
		for key,value in pairs(statScalingList) do
			if statValue >= key and key > highest then
				modificationAmount = value
				highest = key
			end
		end
		if subtractStat > 0 then
			local subtractStatValue = IEex_GetActorStat(targetID, subtractStat)
			local subtractModificationAmount = 0
			highest = -1
			for key,value in pairs(statScalingList) do
				if subtractStatValue >= key and key > highest then
					subtractModificationAmount = value
					highest = key
				end
			end
			modificationAmount = modificationAmount - subtractModificationAmount
			if modificationAmount < 0 then
				modificationAmount = 0
			end
		end
		if ex_stat_offset[modifiedStat][2] == 1 then
			local modifiedStatValue = IEex_ReadSignedByte(creatureData + ex_stat_offset[modifiedStat][1], 0x0) + modificationAmount
			IEex_WriteByte(creatureData + ex_stat_offset[modifiedStat][1], modifiedStatValue)
			IEex_WriteByte(creatureData + ex_stat_offset[modifiedStat][1] + 0xE58, modifiedStatValue)
		elseif ex_stat_offset[modifiedStat][2] == 2 then
			local modifiedStatValue = IEex_ReadSignedWord(creatureData + ex_stat_offset[modifiedStat][1], 0x0) + modificationAmount
			IEex_WriteWord(creatureData + ex_stat_offset[modifiedStat][1], modifiedStatValue)
			IEex_WriteWord(creatureData + ex_stat_offset[modifiedStat][1] + 0xE58, modifiedStatValue)
		elseif ex_stat_offset[modifiedStat][2] == 4 then
			local modifiedStatValue = IEex_ReadDword(creatureData + ex_stat_offset[modifiedStat][1]) + modificationAmount
			IEex_WriteDword(creatureData + ex_stat_offset[modifiedStat][1], modifiedStatValue)
			IEex_WriteDword(creatureData + ex_stat_offset[modifiedStat][1] + 0xE58, modifiedStatValue)
		end
	end
end

function MESPLSTC(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local modifiedStat = IEex_ReadDword(effectData + 0x1C)
	local spellState1 = IEex_ReadByte(effectData + 0x44, 0x0)
	local spellState2 = IEex_ReadByte(effectData + 0x45, 0x0)
	local spellState3 = IEex_ReadByte(effectData + 0x46, 0x0)
	local spellState4 = IEex_ReadByte(effectData + 0x47, 0x0)
	local statValue = IEex_GetActorStat(targetID, modifiedStat)
	if IEex_GetActorSpellState(targetID, spellState1) or (spellState2 ~= 0 and IEex_GetActorSpellState(targetID, spellState2)) or (spellState3 ~= 0 and IEex_GetActorSpellState(targetID, spellState3)) or (spellState4 ~= 0 and IEex_GetActorSpellState(targetID, spellState4)) then
		if ex_stat_offset[modifiedStat][2] == 1 then
			IEex_WriteByte(creatureData + ex_stat_offset[modifiedStat][1], IEex_ReadSignedByte(creatureData + ex_stat_offset[modifiedStat][1], 0x0) + parameter1)
		elseif ex_stat_offset[modifiedStat][2] == 2 then
			IEex_WriteWord(creatureData + ex_stat_offset[modifiedStat][1], IEex_ReadSignedWord(creatureData + ex_stat_offset[modifiedStat][1], 0x0) + parameter1)
		elseif ex_stat_offset[modifiedStat][2] == 4 then
			IEex_WriteDword(creatureData + ex_stat_offset[modifiedStat][1], IEex_ReadDword(creatureData + ex_stat_offset[modifiedStat][1]) + parameter1)
		end
	end
end

function MEHALFTH(effectData, creatureData, isSpecialCall)
	MESTATSC(effectData, creatureData, isSpecialCall)
end

function MESTATSP(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local statValue = 0
	local stat = IEex_ReadWord(effectData + 0x18, 0)
	local otherStat = IEex_ReadByte(effectData + 0x1A, 0)
	local subtractStat = IEex_ReadByte(effectData + 0x1B, 0)
	local index = IEex_ReadWord(effectData + 0x1C, 0)
	local readType = IEex_ReadWord(effectData + 0x1E, 0)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	if readType == 0 then
		statValue = IEex_GetActorStat(targetID, stat)
		if otherStat > 0 then
			local otherStatValue = IEex_GetActorStat(targetID, otherStat)
			if otherStatValue > statValue then
				statValue = otherStatValue
			end
		end
		if subtractStat > 0 then
			statValue = statValue - IEex_GetActorStat(targetID, subtractStat)
		end
	elseif readType == 1 then
		statValue = IEex_ReadSignedByte(creatureData + stat, 0)
	elseif readType == 2 then
		statValue = IEex_ReadSignedWord(creatureData + stat, 0)
	elseif readType == 4 then
		statValue = IEex_ReadDword(creatureData + stat)
	end
	statValue = statValue + IEex_ReadDword(effectData + 0x44)
	if bit.band(savingthrow, 0x10000) > 0 then
		statValue = statValue + IEex_ReadByte(creatureData + 0x78A, 0) * 3
	end
--	IEex_ApplyStatSpell(targetID, index, statValue)
	if statValue < 0 then
		statValue = 0
	end
	local statSpellList = ex_stat_spells[index]
	if statSpellList ~= nil then
		local spellRES = ""
		local highest = -1
		local lowest = 0xFFFFFFFF
		for key,value in pairs(statSpellList) do
			if (bit.band(savingthrow, 0x20000) == 0 and statValue >= key and key > highest) or (bit.band(savingthrow, 0x20000) > 0 and statValue < key and key < lowest) then
				spellRES = value
				highest = key
				lowest = key
			end
		end
		if spellRES ~= "" then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 0,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_target"] = targetID,
["source_id"] = sourceID,
})
		end
	end
end

function MEKITSPL(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then
		sourceID = targetID
	end
	local kit = IEex_GetActorStat(sourceID, 89)
	local index = IEex_ReadWord(effectData + 0x1C, 0)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local kitSpellList = ex_kit_spells[index]
	if kitSpellList ~= nil then
		local spellRES = ""
		for key,value in pairs(kitSpellList) do
			if bit.band(kit, key) > 0 then
				spellRES = value
			end
		end
		if spellRES ~= "" then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 0,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_target"] = targetID,
["source_id"] = sourceID,
})
		end
	end
end

function MERAGE(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local sourceData = IEex_GetActorShare(sourceID)
	local targetID = IEex_GetActorIDShare(creatureData)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	if timing == 4096 then
		duration = math.floor((duration - time_applied) / 15)
	end
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local barbarianLevel = IEex_GetActorStat(targetID, 96)
	local baseBonus = 0
	if barbarianLevel >= 29 then
		baseBonus = 12
	elseif barbarianLevel >= 25 then
		baseBonus = 10
	elseif barbarianLevel >= 21 then
		baseBonus = 8
	elseif barbarianLevel >= 15 then
		baseBonus = 6
	elseif barbarianLevel >= 1 then
		baseBonus = 4
	end
	local willBonus = math.floor(baseBonus / 2)
	baseBonus = baseBonus + IEex_ReadByte(creatureData + 0x789, 0)
	if bit.band(savingthrow, 0x10000) > 0 and timing == 4096 then
		local constitutionBonus = math.floor((IEex_GetActorStat(targetID, 41) + baseBonus - 10) / 2)
		duration = duration + constitutionBonus * 7
		IEex_IterateActorEffects(targetID, function(eData)
			local thetiming = IEex_ReadDword(eData + 0x24)
			local theduration = IEex_ReadDword(eData + 0x28)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theparent_resource == parent_resource and (thetiming == 4096 or thetiming == 6 or thetiming == 7) then
				IEex_WriteDword(eData + 0x28, theduration + constitutionBonus * 105)
			end
		end)
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter1"] = baseBonus,
["special"] = 36,
["resource"] = "MEMODSTA",
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter1"] = baseBonus,
["special"] = 41,
["resource"] = "MEMODSTA",
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
--[[
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 44,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter1"] = baseBonus,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 10,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter1"] = baseBonus,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
--]]
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 35,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter1"] = willBonus,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
end

function MECLSCAS(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local casterlvl = IEex_GetActorStat(sourceID, IEex_ReadDword(effectData + 0x44))
	if casterlvl <= 0 then
		casterlvl = 1
	end
	if spellRES ~= "" then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterlvl,
["parent_resource"] = spellRES,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_id"] = sourceID
})
	end
end

function MEBLARV(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local casterlvl = IEex_GetActorStat(sourceID, 101)
	if casterlvl <= 0 then
		casterlvl = 1
	end
	local isSlaver = (bit.band(IEex_ReadDword(creatureData + 0x740), 0x200000) > 0)
	local race = IEex_ReadByte(creatureData + 0x26, 0x0)
	local subrace = IEex_GetActorStat(targetID, 93)
	if (race == 2 and subrace == 1) or (race == 4 and subrace == 2) then
		isSlaver = true
	end
	if spellRES ~= "" then
		if isSlaver then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterlvl,
["parent_resource"] = spellRES,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_id"] = sourceID
})
		end
	end
end

function METURNUN(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local sourceData = IEex_GetActorShare(sourceID)
	local targetID = IEex_GetActorIDShare(creatureData)
	local targetGeneral = IEex_ReadByte(creatureData + 0x25, 0)
	local targetRace = IEex_ReadByte(creatureData + 0x26, 0)
	if targetGeneral ~= 4 and (targetRace ~= ex_fiend_race or bit.band(IEex_ReadDword(sourceData + 0x760), 0x2) == 0) then return end
	local duration = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local clericLevel = IEex_GetActorStat(sourceID, 98)
	local paladinLevel = IEex_GetActorStat(sourceID, 102)
	local charismaBonus = math.floor((IEex_GetActorStat(sourceID, 42) - 10) / 2)
	local turnLevel = clericLevel + charismaBonus + IEex_ReadDword(effectData + 0x18)
	if paladinLevel >= 3 then
		turnLevel = turnLevel + paladinLevel - 2
	end
	local turnCheck = math.random(20) + charismaBonus
	if turnCheck <= 0 then
		turnLevel = turnLevel - 4
	elseif turnCheck >= 22 then
		turnLevel = turnLevel + 4
	else
		turnLevel = turnLevel + math.floor((turnCheck - 1) / 3) - 3
	end
	local targetLevel = IEex_GetActorStat(targetID, 95) + IEex_ReadSignedByte(creatureData + 0x733, 0x0)
	local baseTargetLevel = IEex_GetActorStat(targetID, 95)
	local preBolsterTargetLevel = targetLevel
	local cea = IEex_CompareActorAllegiances(sourceID, targetID)
	local dispelEnemyTurning = false
	local enemyTurningCheck = 0x7FFFFFFF
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 288 and theparameter2 == 194 and bit.band(thesavingthrow, 0x10000) == 0 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			turnLevel = turnLevel + theparameter1
		end
	end)
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
		local thesourceID = IEex_ReadDword(eData + 0x110)
		if theopcode == 288 and theparameter2 == 194 and bit.band(thesavingthrow, 0x10000) > 0 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			targetLevel = targetLevel + theparameter1
			if theparent_resource ~= "USTURNUB" or thesourceID ~= sourceID then
				preBolsterTargetLevel = preBolsterTargetLevel + theparameter1
			end
		elseif (theopcode == 236 and theparent_resource == "USTURNUN" and cea == 1) or (theopcode == 263 and theparent_resource == "USTURNUN" and cea == -1) then
			dispelEnemyTurning = true
			enemyTurningCheck = IEex_ReadDword(eData + 0x60)
		end
	end)
	local turningFeat = IEex_ReadByte(sourceData + 0x78C, 0)
	turnLevel = turnLevel + turningFeat * 3
	local sourceAlignment = IEex_ReadByte(sourceData + 0x35, 0)
	local sourceKit = IEex_GetActorStat(sourceID, 89)
	local channelsNegativeEnergy = (bit.band(sourceAlignment, 0x3) == 0x3 or (bit.band(sourceAlignment, 0x3) == 0x2 and (sourceKit == 0x200000 or sourceKit == 0x400000 or sourceKit == 0x800000)))
	if channelsNegativeEnergy and dispelEnemyTurning then
		if turnCheck >= enemyTurningCheck and turnLevel >= baseTargetLevel then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["resource"] = "USTURNUN",
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
		end
	elseif channelsNegativeEnergy and not dispelEnemyTurning and cea == 1 then
		if turnLevel >= preBolsterTargetLevel then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["savingthrow"] = 0x10000,
["resource"] = "MEPSTACK",
["parent_resource"] = "USTURNUB",
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 8,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["parent_resource"] = "USTURNUB",
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter1"] = turnLevel - preBolsterTargetLevel,
["parameter2"] = 194,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["savingthrow"] = 0x10000,
["parent_resource"] = "USTURNUB",
["source_id"] = sourceID
})
			if turnLevel > targetLevel then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = ex_tra_55717,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["parent_resource"] = "USTURNUB",
["source_id"] = sourceID
})
			end
		end
	elseif turnLevel >= targetLevel * 2 then
		if channelsNegativeEnergy then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 8,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 263,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter2"] = 4,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter2"] = 67,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
		elseif IEex_GetActorSpellState(targetID, 8) == false then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 8,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter2"] = 67,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 13,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 1,
["parameter2"] = 0x4,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
		end
	elseif turnLevel > targetLevel then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 8,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 236,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter2"] = 67,
["parameter3"] = turnCheck,
["parameter4"] = turnLevel,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
	end
end

function METURNU2(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local sourceData = IEex_GetActorShare(sourceID)
	local targetID = IEex_GetActorIDShare(creatureData)
	local duration = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local sourceLevel = IEex_GetActorStat(sourceID, 98)
	local paladinLevel = IEex_GetActorStat(sourceID, 102)
	if paladinLevel >= 3 then
		sourceLevel = sourceLevel + paladinLevel - 2
	end
	local charismaBonus = math.floor((IEex_GetActorStat(sourceID, 42) - 10) / 2)
	local turnLevel = math.random(6) + math.random(6) + sourceLevel + charismaBonus + IEex_ReadDword(effectData + 0x18)
	local maxUndeadLevel = sourceLevel

	local turnCheck = math.random(20) + charismaBonus
	if turnCheck <= 0 then
		maxUndeadLevel = maxUndeadLevel - 4
	elseif turnCheck >= 22 then
		maxUndeadLevel = maxUndeadLevel + 4
	else
		maxUndeadLevel = maxUndeadLevel + math.floor((turnCheck - 1) / 3) - 3
	end
	if IEex_GetActorSpellState(sourceID, 194) then
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 194 and bit.band(thesavingthrow, 0x10000) == 0 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				turnLevel = turnLevel + theparameter1
				maxUndeadLevel = maxUndeadLevel + theparameter1
			end
		end)
	end
	local turningFeat = IEex_ReadByte(sourceData + 0x78C, 0)
	turnLevel = turnLevel + turningFeat * 3
	maxUndeadLevel = maxUndeadLevel + turningFeat * 3
	local sourceAlignment = IEex_ReadByte(sourceData + 0x35, 0)
	local sourceKit = IEex_GetActorStat(sourceID, 89)
	if sourceID ~= targetID then
		local targetGeneral = IEex_ReadByte(creatureData + 0x25, 0)
		local targetRace = IEex_ReadByte(creatureData + 0x26, 0)
		if targetGeneral ~= 4 and (targetRace ~= ex_fiend_race or bit.band(IEex_ReadDword(sourceData + 0x760), 0x2) == 0) then return end
		local targetLevel = IEex_GetActorStat(targetID, 95) + IEex_ReadSignedByte(creatureData + 0x733, 0x0)
		if IEex_GetActorSpellState(targetID, 194) then
			IEex_IterateActorEffects(targetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				if theopcode == 288 and theparameter2 == 194 and bit.band(thesavingthrow, 0x10000) > 0 then
					local theparameter1 = IEex_ReadDword(eData + 0x1C)
					targetLevel = targetLevel + theparameter1
				end
			end)
		end
		if turnLevel >= targetLevel then
			if maxUndeadLevel >= targetLevel * 2 then
				if bit.band(sourceAlignment, 0x3) == 0x3 or (bit.band(sourceAlignment, 0x3) == 0x2 and (sourceKit == 0x200000 or sourceKit == 0x400000 or sourceKit == 0x800000)) then
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 8,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 263,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter2"] = 4,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter2"] = 67,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
				elseif IEex_GetActorSpellState(targetID, 8) == false then
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 8,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter2"] = 67,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 13,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 1,
["parameter2"] = 0x4,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
				end
			elseif maxUndeadLevel >= targetLevel then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 8,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 236,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter2"] = 67,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
			end
		end
	else
		local maxradius = IEex_ReadDword(effectData + 0x44)
		if maxradius == 0 then
			maxradius = 384
		end
		local ids = {}
		if IEex_ReadDword(sourceData + 0x12) > 0 then
			ids = IEex_GetIDArea(sourceID, 0x31)
		end
		local possibleTargets = {}
		local sourceX, sourceY = IEex_GetActorLocation(sourceID)
		for k, currentID in ipairs(ids) do
			local currentShare = IEex_GetActorShare(currentID)
			if currentShare > 0 then
				local currentX, currentY = IEex_GetActorLocation(currentID)
				local currentDistance = IEex_GetDistance(targetX, targetY, currentX, currentY)
				local states = IEex_ReadDword(currentShare + 0x5BC)
				local animation = IEex_ReadDword(currentShare + 0x5C4)
				local cea = IEex_CompareActorAllegiances(sourceID, currentID)
				local targetGeneral = IEex_ReadByte(currentShare + 0x25, 0)
				local targetRace = IEex_ReadByte(currentShare + 0x26, 0)

				if currentDistance < maxradius and cea == -1 and IEex_CheckActorLOSObject(sourceID, currentID) and animation >= 0x1000 and (animation < 0xD000 or animation >= 0xE000) and bit.band(states, 0x800) == 0 and IEex_ReadByte(currentShare + 0x838, 0x0) == 0 and (targetGeneral == 4 or (targetRace == ex_fiend_race and bit.band(IEex_ReadDword(sourceData + 0x760), 0x2) > 0)) then
					table.insert(possibleTargets, {currentID, currentDistance})
				end
			end
		end
		table.sort(possibleTargets, function(i1, i2) return (i1[2] < i2[2]) end)
		for k, current in ipairs(possibleTargets) do
			local currentID = current[1]
			local currentShare = IEex_GetActorShare(currentID)
			local targetLevel = IEex_GetActorStat(currentID, 95) + IEex_ReadSignedByte(currentShare + 0x733, 0x0)
			if IEex_GetActorSpellState(currentID, 194) then
				IEex_IterateActorEffects(currentID, function(eData)
					local theopcode = IEex_ReadDword(eData + 0x10)
					local theparameter2 = IEex_ReadDword(eData + 0x20)
					local thesavingthrow = IEex_ReadDword(eData + 0x40)
					if theopcode == 288 and theparameter2 == 194 and bit.band(thesavingthrow, 0x10000) > 0 then
						local theparameter1 = IEex_ReadDword(eData + 0x1C)
						targetLevel = targetLevel + theparameter1
					end
				end)
			end
			if turnLevel >= targetLevel then
				if maxUndeadLevel >= targetLevel * 2 then
					turnLevel = turnLevel - targetLevel
					if bit.band(sourceAlignment, 0x3) == 0x3 or (bit.band(sourceAlignment, 0x3) == 0x2 and (sourceKit == 0x200000 or sourceKit == 0x400000 or sourceKit == 0x800000)) then
						IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 8,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
						IEex_ApplyEffectToActor(targetID, {
["opcode"] = 263,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter2"] = 4,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
						IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter2"] = 67,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
					elseif IEex_GetActorSpellState(targetID, 8) == false then
						IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 8,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
						IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter2"] = 67,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
						IEex_ApplyEffectToActor(targetID, {
["opcode"] = 13,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 1,
["parameter2"] = 0x4,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
					end
				elseif maxUndeadLevel >= targetLevel then
					turnLevel = turnLevel - targetLevel
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 8,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 236,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter2"] = 67,
["parent_resource"] = "USTURNUN",
["source_id"] = sourceID
})
				end
			end
		end
	end
end

function MESMITEH(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local duration = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local charismaBonus = math.floor((IEex_GetActorStat(targetID, 42) - 10) / 2)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 178,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter1"] = 3,
["parameter2"] = 8,
["parameter3"] = charismaBonus,
["parent_resource"] = "USSMITEH",
["source_id"] = targetID
})
end

function MESMITE(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(sourceID, false) then return end
	local sourceData = IEex_GetActorShare(sourceID)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local special = IEex_ReadDword(effectData + 0x44)
	local targetAlignment = IEex_ReadByte(creatureData + 0x35, 0x0)
	if special == 0 and bit.band(targetAlignment, 0x3) ~= 0x3 then
		return
	elseif special == 1 and bit.band(targetAlignment, 0x3) ~= 0x1 then
		return
	end
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local paladinLevel = IEex_GetActorStat(sourceID, 102)
	local charismaBonus = math.floor((IEex_GetActorStat(sourceID, 42) - 10) / 2)
--[[
	local extraDamage = paladinLevel + charismaBonus
	local smitingFeat = IEex_ReadByte(sourceData + 0x78B, 0)
	extraDamage = extraDamage + extraDamage * smitingFeat
--]]
	local diceSize = IEex_ReadByte(effectData + 0x19, 0x0)
	if diceSize == 0 then
		diceSize = 4
	end
	local extraDice = charismaBonus
	local smitingFeat = IEex_ReadByte(sourceData + 0x78B, 0)
	extraDice = extraDice + extraDice * smitingFeat + paladinLevel + IEex_ReadByte(effectData + 0x1A, 0x0)
	local newsavingthrow = 0x10000
	if bit.band(savingthrow, 0x4000000) > 0 then
		newsavingthrow = bit.bor(newsavingthrow, 0x4000000)
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = IEex_ReadByte(effectData + 0x18, 0x0) + diceSize * 0x100 + extraDice * 0x10000,
["parameter2"] = parameter2,
["savingthrow"] = newsavingthrow,
["resource"] = "EXDAMAGE",
["parent_resource"] = parent_resource,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 0,
["resource"] = "USSMITEH",
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
end

function MEHOLYMI(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local statValue = IEex_ReadDword(effectData + 0x44)

	local index = IEex_ReadWord(effectData + 0x1C, 0)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0)
	if casterClass == 7 then
		statValue = statValue + math.floor((IEex_GetActorStat(targetID, 42) - 10) / 2)
	end
	IEex_ApplyStatSpell(targetID, index, statValue)
end

function MEPALSPL(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local special = IEex_ReadDword(effectData + 0x44)
	local casterlvl = IEex_ReadByte(effectData + 0xC4, 0)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0)
	if casterClass == 7 or casterClass == 8 then
		casterlvl = IEex_GetActorStat(sourceID, 95 + casterClass)
		if casterlvl == 0 then
			casterlvl = 1
		end
	end
	if bit.band(savingthrow, 0x1000000) > 0 and casterClass == 7 then
		casterlvl = casterlvl + special
	end
	if bit.band(savingthrow, 0x2000000) > 0 and casterClass == 8 then
		casterlvl = casterlvl + special
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 0,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["casterlvl"] = casterlvl,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_target"] = targetID,
["source_id"] = sourceID,
})
end

function MEPERFEC(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
--	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local statValue = IEex_ReadDword(effectData + 0x44)
	statValue = statValue + math.floor((IEex_GetActorStat(targetID, 38) - 10) / 2)
	statValue = statValue + math.floor((IEex_GetActorStat(targetID, 39) - 10) / 2)
	statValue = statValue + math.floor((IEex_GetActorStat(targetID, 40) - 10) / 2)
	statValue = statValue + math.floor((IEex_GetActorStat(targetID, 41) - 10) / 2)
	statValue = statValue + math.floor((IEex_GetActorStat(targetID, 42) - 10) / 2)
--	local index = IEex_ReadWord(effectData + 0x1C, 0)
--	IEex_ApplyStatSpell(targetID, index, statValue)
	IEex_WriteWord(creatureData + 0x9A6, IEex_ReadSignedWord(creatureData + 0x9A6, 0x0) + statValue)
end

function MESTATRO(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local stat = IEex_ReadWord(effectData + 0x44, 0x0)
	local statValue = IEex_GetActorStat(targetID, stat)
	local dc = IEex_ReadWord(effectData + 0x46, 0x0)
	local roll = math.random(20)
	local invert = (bit.band(IEex_ReadDword(effectData + 0x3C), 0x100000) > 0)
	if roll > 1 and (roll == 20 or statValue + roll >= dc) then
		if invert == false then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if spellRES ~= "" then
				IEex_ApplyResref(spellRES, targetID)
			end
		end
	else
		if invert == true then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if spellRES ~= "" then
				IEex_ApplyResref(spellRES, targetID)
			end
		end
	end
end

function MESTATES(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local state = IEex_ReadDword(effectData + 0x44)
	local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
	local invert = (bit.band(IEex_ReadDword(effectData + 0x3C), 0x100000) > 0)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	if bit.band(stateValue, state) ~= 0 then
		if invert == false then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if spellRES ~= "" then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterlvl,
["parent_resource"] = spellRES,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_id"] = sourceID
})
			end
		end
	else
		if invert == true then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if spellRES ~= "" then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterlvl,
["parent_resource"] = spellRES,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_id"] = sourceID
})
			end
		end
	end
end

function MESTATEI(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
	local invert = (bit.band(IEex_ReadDword(effectData + 0x3C), 0x100000) > 0)
	if bit.band(stateValue, 0x10) > 0 and bit.band(IEex_ReadByte(creatureData + 0x8A0, 0x0), 0x1) == 0 then
		if invert == false then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if spellRES ~= "" then
				IEex_ApplyResref(spellRES, targetID)
			end
		end
	else
		if invert == true then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if spellRES ~= "" then
				IEex_ApplyResref(spellRES, targetID)
			end
		end
	end
end

function MEKILLSP(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
	local invert = (bit.band(IEex_ReadDword(effectData + 0x3C), 0x100000) > 0)
	if bit.band(stateValue, 0xFC0) > 0 then
		if invert == false then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if bit.band(stateValue, 0xC0) > 0 then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 13,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 1,
["parameter2"] = 0x40,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["source_id"] = sourceID
})
			end
			if spellRES ~= "" then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["parent_resource"] = spellRES,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_id"] = sourceID
})
			end
		end
	else
		if invert == true then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if bit.band(stateValue, 0xC0) > 0 then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 13,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 1,
["parameter2"] = 0x40,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["source_id"] = sourceID
})
			end
			if spellRES ~= "" then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["parent_resource"] = spellRES,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_id"] = sourceID
})
			end
		end
	end
end

function MESPLSTS(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local spellState1 = IEex_ReadByte(effectData + 0x44, 0x0)
	local spellState2 = IEex_ReadByte(effectData + 0x45, 0x0)
	local spellState3 = IEex_ReadByte(effectData + 0x46, 0x0)
	local spellState4 = IEex_ReadByte(effectData + 0x47, 0x0)
	local invert = (bit.band(IEex_ReadDword(effectData + 0x3C), 0x100000) > 0)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	if IEex_GetActorSpellState(targetID, spellState1) or (spellState2 > 0 and IEex_GetActorSpellState(targetID, spellState2)) or (spellState3 > 0 and IEex_GetActorSpellState(targetID, spellState3)) or (spellState4 > 0 and IEex_GetActorSpellState(targetID, spellState4)) then
		if invert == false then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if spellRES ~= "" then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterlvl,
["parent_resource"] = spellRES,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_id"] = sourceID
})
			end
		end
	else
		if invert == true then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if spellRES ~= "" then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterlvl,
["parent_resource"] = spellRES,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_id"] = sourceID
})
			end
		end
	end
end

function MEMOVSPL(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["source_id"] = targetID
})
	local destinationX = IEex_ReadDword(creatureData + 0x556E)
	local destinationY = IEex_ReadDword(creatureData + 0x5572)
	local invert = (bit.band(IEex_ReadDword(effectData + 0x3C), 0x100000) > 0)
	if destinationX > 0 or destinationY > 0 then
		if invert == false then
			if spellRES ~= "" then
				IEex_ApplyResref(spellRES, targetID)
			end
		end
	else
		if invert == true then
			if spellRES ~= "" then
				IEex_ApplyResref(spellRES, targetID)
			end
		end
	end
end

function MERACESP(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
--	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local matchRace = IEex_ReadByte(effectData + 0x44, 0x0)
	local matchSubrace = IEex_ReadByte(effectData + 0x45, 0x0)
	local invert = (bit.band(IEex_ReadDword(effectData + 0x3C), 0x100000) > 0)
	if matchRace == IEex_ReadByte(creatureData + 0x26, 0x0) and (matchSubrace == 0 or matchSubrace == IEex_GetActorStat(targetID, 93) + 1) then
		if invert == false then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if spellRES ~= "" then
				IEex_ApplyResref(spellRES, targetID)
			end
		end
	else
		if invert == true then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if spellRES ~= "" then
				IEex_ApplyResref(spellRES, targetID)
			end
		end
	end
end

function MEACTSPL(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(sourceID, false) then return end
	local action = IEex_ReadWord(effectData + 0x44, 0x0)
	local invert = (bit.band(IEex_ReadDword(effectData + 0x3C), 0x100000) > 0)
	if (action ~= IEex_ReadWord(creatureData + 0x476, 0x0) and not invert) or action == IEex_ReadWord(creatureData + 0x476, 0x0) and invert then return end
	local targetID = IEex_ReadDword(creatureData + 0x4BE)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	if casterlvl <= 1 then
		casterlvl = IEex_GetActorStat(sourceID, 95)
	end
	local sourceX = IEex_ReadDword(creatureData + 0x6)
	local sourceY = IEex_ReadDword(creatureData + 0xA)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local range = IEex_ReadWord(effectData + 0x46, 0x0)
	local invertRangeCheck = (bit.band(savingthrow, 0x200000) > 0)
	local checkLineOfSight = (bit.band(savingthrow, 0x400000) > 0)
	local targetData = IEex_GetActorShare(targetID)
	if targetData > 0 then
		local targetX = IEex_ReadDword(targetData + 0x6)
		local targetY = IEex_ReadDword(targetData + 0xA)
		if range > 0 then
			if invertRangeCheck then
				if IEex_GetDistance(sourceX, sourceY, targetX, targetY) < range then return end
			else
				if IEex_GetDistance(sourceX, sourceY, targetX, targetY) >= range then return end
			end
		end
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 0,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["casterlvl"] = casterlvl,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_target"] = targetID,
["source_id"] = sourceID,
["source_x"] = sourceX,
["source_y"] = sourceY,
["target_x"] = targetX,
["target_y"] = targetY
})
	else
		local targetX = IEex_ReadDword(creatureData + 0x540)
		local targetY = IEex_ReadDword(creatureData + 0x544)
		if range > 0 then
			if invertRangeCheck then
				if IEex_GetDistance(sourceX, sourceY, targetX, targetY) < range then return end
			else
				if IEex_GetDistance(sourceX, sourceY, targetX, targetY) >= range then return end
			end
		end
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 0,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["casterlvl"] = casterlvl,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_target"] = sourceID,
["source_id"] = sourceID,
["source_x"] = sourceX,
["source_y"] = sourceY,
["target_x"] = targetX,
["target_y"] = targetY
})
	end

end

function MECSCORC(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local internalFlags = 0x20
	if IEex_IsSprite(sourceID, false) then
		IEex_IterateProjectiles(targetID, 108, function(share)
			if IEex_ReadDword(share + 0x72) == sourceID then
				parent_resource = IEex_ReadLString(share + 0x18A, 8)
				if parent_resource == "" then
					local projectileSourceID = IEex_ReadDword(share + 0x72)
					if IEex_Helper_GetBridge("IEex_RecordOpcode430Spell", sourceID, "spellRES") ~= nil then
						parent_resource = IEex_Helper_GetBridge("IEex_RecordOpcode430Spell", sourceID, "spellRES")
					end
				end
				if ex_projectile_flags[share] ~= nil then
					internalFlags = bit.bor(ex_projectile_flags[share]["Metamagic"], 0x20)
				end
			end
		end)
	end
	if bit.band(savingthrow, 0x10000) == 0 then
		local spellRES = ex_custom_scorcher["DEFAULT"]["TargetSpell"]
		if ex_custom_scorcher[parent_resource] ~= nil then
			spellRES = ex_custom_scorcher[parent_resource]["TargetSpell"]
		end
		if spellRES ~= "" then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterlvl,
["internal_flags"] = internalFlags,
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
		end
	else
		local spellRES = ex_custom_scorcher["DEFAULT"]["PathSpell"]
		if ex_custom_scorcher[parent_resource] ~= nil then
			spellRES = ex_custom_scorcher[parent_resource]["PathSpell"]
		end
		if spellRES ~= "" then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterlvl,
["internal_flags"] = internalFlags,
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
		end
	end
end

function MELINESP(effectData, creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local maxDistance = IEex_ReadDword(effectData + 0x44)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local sourceX = IEex_ReadDword(creatureData + 0x6)
	local sourceY = IEex_ReadDword(creatureData + 0xA)
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local deltaX = targetX - sourceX
	local deltaY = targetY - sourceY
	local areaX = 0
	local areaY = 0
	local areaData = IEex_ReadDword(creatureData + 0x12)
	if areaData > 0 then
		areaX = IEex_ReadDword(areaData + 0x54C)
		areaY = IEex_ReadDword(areaData + 0x550)
	end
	if areaX <= 0 or areaY <= 0 then return end
	local newTargetX = targetX
	local newTargetY = targetY
	if deltaX > 0 then
		newTargetY = deltaY / deltaX * (areaX - sourceX) + sourceY
	elseif deltaX < 0 then
		newTargetY = deltaY / deltaX * -sourceX + sourceY
	end
	if deltaY > 0 then
		newTargetX = deltaX / deltaY * (areaY - sourceY) + sourceX
	elseif deltaY < 0 then
		newTargetX = deltaX / deltaY * -sourceY + sourceX
	end
--[[
	if deltaX > 0 and deltaY > 0 then
		newTargetX = deltaX / deltaY * (areaY - sourceY) + sourceX
		newTargetY = deltaY / deltaX * (areaX - sourceX) + sourceY
	elseif deltaX < 0 and deltaY > 0 then
		newTargetX = deltaX / deltaY * (areaY - sourceY) + sourceX
		newTargetY = deltaY / deltaX * -sourceX
	end
--]]
	if newTargetX < 0 then
		newTargetX = 0
	elseif newTargetX > areaX then
		newTargetX = areaX
	end
	if newTargetY < 0 then
		newTargetY = 0
	elseif newTargetY > areaY then
		newTargetY = areaY
	end

	local deltaH = math.floor((deltaX ^ 2 + deltaY ^ 2) ^ .5)
	if maxDistance > 0 then
		local maxX = deltaX / deltaH * maxDistance + sourceX
		local maxY = deltaY / deltaH * maxDistance + sourceY
		if maxX > 0 and maxX < areaX and maxY > 0 and maxY < areaY then
			newTargetX = maxX
			newTargetY = maxY
		end
	end
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 148,
["target"] = 2,
["timing"] = 1,
["parameter1"] = casterlvl,
["parameter2"] = 1,
["casterlvl"] = casterlvl,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["internal_flags"] = internalFlags,
["source_x"] = sourceX,
["source_y"] = sourceY,
["target_x"] = newTargetX,
["target_y"] = newTargetY,
["source_target"] = sourceID,
["source_id"] = sourceID
})
end

function MERAGEST(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "MERAGEST",
["source_id"] = targetID
})
	if IEex_GetActorSpellState(targetID, 159) or IEex_GetActorSpellState(targetID, 160) then
		local barbarianLevel = IEex_GetActorStat(targetID, 96)
		local baseBonus = 0
		if barbarianLevel >= 29 then
			baseBonus = 12
		elseif barbarianLevel >= 25 then
			baseBonus = 10
		elseif barbarianLevel >= 21 then
			baseBonus = 8
		elseif barbarianLevel >= 15 then
			baseBonus = 6
		elseif barbarianLevel >= 1 then
			baseBonus = 4
		end
		baseBonus = baseBonus + IEex_ReadByte(creatureData + 0x789, 0)
		if bit.band(parameter2, 0x1) > 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 44,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = baseBonus + parameter1,
["parent_resource"] = "MERAGEST",
["source_id"] = targetID
})
		end
		if bit.band(parameter2, 0x2) > 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 10,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = baseBonus + parameter1,
["parent_resource"] = "MERAGEST",
["source_id"] = targetID
})
		end
	end
end

function MEBARRAG(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	IEex_WriteDword(effectData + 0x110, 1)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceData = 0
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	local barrageCount = IEex_ReadWord(effectData + 0x44, 0x0)
	local projectile = IEex_ReadWord(effectData + 0x46, 0x0)
	if bit.band(savingthrow, 0x10000000) > 0 then
		parent_resource = spellRES
	end
	ex_projectile_redirect[sourceID] = targetID
--[[
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 430,
["target"] = 2,
["timing"] = 1,
["parameter2"] = projectile,
["casterlvl"] = casterlvl,
["resource"] = spellRES,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
--]]
	for i = 1, 60, 1 do
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 430,
["target"] = 2,
["timing"] = 6,
--["duration"] = IEex_GetGameTick() + (i * 2) - 1,
["parameter2"] = projectile,
["casterlvl"] = casterlvl,
["resource"] = spellRES,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
	end
--[[
	for i = 1, barrageCount, 1 do
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 146,
["target"] = 2,
["timing"] = 1,
["duration"] = IEex_GetGameTick() + i - 1,
["parameter1"] = 1,
["parameter2"] = 1,
["casterlvl"] = casterlvl,
["resource"] = spellRES,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
	end
--]]
end

function MEBARRA2(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
--	if IEex_GetGameTick() % 5 ~= 0 then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceData = 0
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	local barrageCount = IEex_ReadWord(effectData + 0x44, 0x0)
	local projectile = IEex_ReadWord(effectData + 0x46, 0x0)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if barrageCount == 0 then
		IEex_WriteDword(effectData + 0x110, 1)
		return
	elseif barrageCount < 0xFFFF then
		barrageCount = barrageCount - 1
		IEex_WriteWord(effectData + 0x44, barrageCount)
	end
	if bit.band(savingthrow, 0x10000000) > 0 then
		parent_resource = spellRES
	end
	ex_projectile_redirect[sourceID] = targetID
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 430,
["target"] = 2,
["timing"] = 9,
["parameter2"] = projectile,
["casterlvl"] = casterlvl,
["internal_flags"] = internalFlags,
["resource"] = spellRES,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
--]]
end

function MEBARRAM(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	IEex_WriteDword(effectData + 0x110, 1)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
--	local targetX = IEex_ReadDword(effectData + 0x84)
--	local targetY = IEex_ReadDword(effectData + 0x88)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	if spellRES == "" then
		spellRES = parent_resource .. "D"
	end
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	local barrageCount = IEex_ReadWord(effectData + 0x44, 0x0)
	local parameter4 = IEex_ReadDword(effectData + 0x60)
	if barrageCount == 0 then
		barrageCount = 1
	end
--	local projectile = IEex_ReadWord(effectData + 0x46, 0x0)
	local currentAngle = 0
	local angleIncrement = 6
	local delta = 100
	local deltaX = 0
	local deltaY = 0
	if bit.band(savingthrow, 0x10000000) > 0 then
		parent_resource = spellRES
	end
	if parameter4 == 0 then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = math.floor(barrageCount / 10) + 1,
["parameter2"] = 250,
["special"] = barrageCount,
["target_x"] = targetX,
["target_y"] = targetY,
["casterlvl"] = casterlvl,
["resource"] = "MEBARRAA",
["vvcresource"] = spellRES,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
	end
	for i = 1, barrageCount, 1 do
		if i > parameter4 then
			deltaX = math.floor(math.cos(currentAngle) * delta)
			deltaY = math.floor(math.sin(currentAngle) * delta)
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 148,
["target"] = 2,
["timing"] = 1,
--["duration"] = IEex_GetGameTick() + i - 1,
["parameter1"] = IEex_ReadByte(effectData + 0xC4, 0x0),
["parameter2"] = 1,
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = targetX + deltaX,
["target_y"] = targetY + deltaY,
["casterlvl"] = casterlvl,
["resource"] = spellRES,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		end
		currentAngle = currentAngle + angleIncrement
	end

end

function MEBARRAA(originatingEffectData, actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	local special = IEex_ReadDword(originatingEffectData + 0x44) * 2
	local parameter4 = IEex_ReadDword(originatingEffectData + 0x60)
	local spellRES = IEex_ReadLString(originatingEffectData + 0x6C, 8)
	local parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
	local targetX = IEex_ReadDword(originatingEffectData + 0x84)
	local targetY = IEex_ReadDword(originatingEffectData + 0x88)
	if spellRES == "" then
		spellRES = parent_resource .. "D"
		IEex_WriteLString(originatingEffectData + 0x6C, spellRES, 8)
	end
	if actionID == 114 and IEex_GetActorSpellRES(sourceID) == spellRES then
		parameter4 = parameter4 + 1
		IEex_WriteDword(originatingEffectData + 0x60, parameter4)
	elseif parameter4 < special then
		IEex_SetActionID(actionData, 0)
		local casterlvl = IEex_ReadDword(originatingEffectData + 0xC4)
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = IEex_ReadDword(originatingEffectData + 0x6C),
["parameter2"] = IEex_ReadDword(originatingEffectData + 0x70),
["parameter4"] = parameter4,
["special"] = special,
["casterlvl"] = casterlvl,
["resource"] = "MEBARRAM",
["parent_resource"] = parent_resource,
["target_x"] = targetX,
["target_y"] = targetY,
["source_id"] = sourceID
})
	end
end

IEex_AddActionHookOpcode("MEBARRAA")

function MEBARRAL(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	IEex_WriteDword(effectData + 0x110, 1)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceData = 0
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	local barrageCount = IEex_ReadWord(effectData + 0x44, 0x0)
	local projectile = IEex_ReadWord(effectData + 0x46, 0x0)
	local ids = IEex_GetIDArea(targetID, 0x31)
	if bit.band(savingthrow, 0x10000000) > 0 then
		parent_resource = spellRES
	end
--[[
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 430,
["target"] = 2,
["timing"] = 1,
["parameter2"] = projectile,
["casterlvl"] = casterlvl,
["resource"] = spellRES,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
--]]
	for i = 1, barrageCount, 1 do
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 430,
["target"] = 2,
["timing"] = 6,
["duration"] = IEex_GetGameTick() + (i * 2) - 1,
["parameter2"] = projectile,
["casterlvl"] = casterlvl,
["resource"] = spellRES,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
	end
--[[
	for i = 1, barrageCount, 1 do
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 146,
["target"] = 2,
["timing"] = 1,
["duration"] = IEex_GetGameTick() + i - 1,
["parameter1"] = 1,
["parameter2"] = 1,
["casterlvl"] = casterlvl,
["resource"] = spellRES,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
	end
--]]
end

function MEGARGOY(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	IEex_WriteDword(effectData + 0x110, 1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local currentAction = IEex_ReadWord(creatureData + 0x476, 0x0)
	if currentAction == 0 and not IEex_GetActorSpellState(targetID, 18) then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 4,
["duration"] = 6,
["resource"] = "USGARGO1",
["parent_resource"] = "USGARGO1",
["source_target"] = targetID,
["source_id"] = targetID
})
	else
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USGARGO1",
["parent_resource"] = "USGARGO1",
["source_target"] = targetID,
["source_id"] = targetID
})
	end
end

function MEGARGOS(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	IEex_WriteDword(effectData + 0x110, 1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local skinType = IEex_ReadDword(effectData + 0x44)
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		if theopcode == 218 then
			if skinType == 0 and theparameter2 == 0 then
				local skinsRemaining = IEex_ReadDword(eData + 0x60)
				if parameter2 == 0 then
					IEex_WriteDword(eData + 0x60, skinsRemaining + parameter1)
				elseif parameter2 == 1 then
					IEex_WriteDword(eData + 0x60, parameter1)
				elseif parameter2 == 2 then
					IEex_WriteDword(eData + 0x60, math.floor(skinsRemaining * parameter1 / 100))
				end
			elseif skinType == 1 and theparameter2 == 1 then
				local skinsRemaining = IEex_ReadDword(eData + 0x1C)
				if parameter2 == 0 then
					IEex_WriteDword(eData + 0x1C, skinsRemaining + parameter1)
				elseif parameter2 == 1 then
					IEex_WriteDword(eData + 0x1C, parameter1)
				elseif parameter2 == 2 then
					IEex_WriteDword(eData + 0x1C, math.floor(skinsRemaining * parameter1 / 100))
				end
			end
		end
	end)
end

function MERAISED(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	IEex_WriteDword(effectData + 0x110, 1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local race = IEex_ReadByte(creatureData + 0x26, 0x0)
	local animation = IEex_ReadDword(creatureData + 0x5C4)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	if bit.band(extraFlags, 0x20000000) > 0 then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = ex_tra_55380,
["parameter2"] = 2,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		return
	elseif bit.band(extraFlags, 0x10000000) > 0 and bit.band(savingthrow, 0x20000) == 0 then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = ex_tra_55379,
["parameter2"] = 2,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		return
	elseif bit.band(savingthrow, 0x40000) > 0 and not IEex_GetActorState(targetID, 0x80) then
		return
	end
	extraFlags = bit.band(extraFlags, 0xEFFFFFFF)
	IEex_WriteDword(creatureData + 0x740, extraFlags)
	if bit.band(savingthrow, 0x10000) > 0 then
		local revivalTicks = IEex_ReadDword(effectData + 0x44) * 15
		local timeOfDeath = IEex_ReadDword(creatureData + 0x704)
		if timeOfDeath == -1 then
			return
		elseif (IEex_GetGameTick() - timeOfDeath) > revivalTicks then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = ex_tra_55381,
["parameter2"] = 2,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
			return
		end
	end
	if race >= 8 then
		IEex_WriteByte(creatureData + 0x26, 1)
		if bit.band(savingthrow, 0x40000) == 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 32,
["target"] = 2,
["timing"] = 9,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		else
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 43,
["target"] = 2,
["timing"] = 9,
["resist_dispel"] = 2,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["resist_dispel"] = 2,
["parameter1"] = 165,
["parameter2"] = -1,
["special"] = -1,
["resource"] = "MEREMOPC",
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		end
		IEex_WriteByte(creatureData + 0x26, race)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 1,
["parameter1"] = animation,
["parameter2"] = 2,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = animation,
["parameter2"] = 0,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
	else
		if bit.band(savingthrow, 0x40000) == 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 32,
["target"] = 2,
["timing"] = 9,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		else
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 43,
["target"] = 2,
["timing"] = 9,
["resist_dispel"] = 2,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["resist_dispel"] = 2,
["parameter1"] = 165,
["parameter2"] = -1,
["special"] = -1,
["resource"] = "MEREMOPC",
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		end
	end
	local constantID = IEex_ReadDword(creatureData + 0x700)
	local equipmentRecord = ex_dead_pc_equipment_record[constantID]
	if equipmentRecord == nil or #equipmentRecord == 0 then return end
	local highestNumMatches = 0
	local numMatches = 0
	local highestNumMatchesContainer = 0
	local areaData = IEex_ReadDword(creatureData + 0x12)
	if areaData == 0 then
		local sourceData = IEex_GetActorShare(sourceID)
		if sourceData > 0 then
			areaData = IEex_ReadDword(sourceData + 0x12)
		end
	end
	IEex_IterateIDs(areaData, 0x11, function(containerID)
		local containerData = IEex_GetActorShare(containerID)
		numMatches = 0
		if IEex_ReadDword(containerData + 0x5BA) <= #equipmentRecord then
			IEex_IterateCPtrList(containerData + 0x5AE, function(containerItemData)
				local nextItem = equipmentRecord[numMatches + 1]
				local itemRES = IEex_ReadLString(containerItemData + 0xC, 8)
				local charges1 = IEex_ReadWord(containerItemData + 0x18, 0x0)
				local charges2 = IEex_ReadWord(containerItemData + 0x1A, 0x0)
				local charges3 = IEex_ReadWord(containerItemData + 0x1C, 0x0)
				local slotFlags = IEex_ReadDword(containerItemData + 0x20)
				if itemRES == nextItem[2] and charges1 == nextItem[3] and charges2 == nextItem[4] and charges3 == nextItem[5] and slotFlags == nextItem[6] then
					numMatches = numMatches + 1
				end
			end)
		end
		if numMatches > highestNumMatches then
			highestNumMatches = numMatches
			highestNumMatchesContainer = containerData
		end
	end)
	if highestNumMatchesContainer > 0 then
		local nextItemIndex = 1
		IEex_IterateCPtrList(highestNumMatchesContainer + 0x5AE, function(containerItemData)
			local itemRES = IEex_ReadLString(containerItemData + 0xC, 8)
			local charges1 = IEex_ReadWord(containerItemData + 0x18, 0x0)
			local charges2 = IEex_ReadWord(containerItemData + 0x1A, 0x0)
			local charges3 = IEex_ReadWord(containerItemData + 0x1C, 0x0)
			local slotFlags = IEex_ReadDword(containerItemData + 0x20)
			for i = nextItemIndex, #equipmentRecord, 1 do
				local nextItem = equipmentRecord[i]
				if itemRES == nextItem[2] and charges1 == nextItem[3] and charges2 == nextItem[4] and charges3 == nextItem[5] and slotFlags == nextItem[6] then
					nextItemIndex = nextItemIndex + 1
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = nextItem[1],
["parameter2"] = 2,
["resource"] = itemRES,
["source_id"] = targetID
})

					if charges1 > 1 or charges2 > 1 or charges3 > 1 then
						IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = charges1,
["parameter2"] = 1,
["parameter3"] = charges2,
["parameter4"] = charges3,
["special"] = nextItem[1],
["savingthrow"] = 0x80000,
["resource"] = "EXCHARGE",
["source_id"] = targetID
})
						
					end
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = slotFlags,
["parameter2"] = 0,
["special"] = nextItem[1],
["resource"] = "EXITMFLG",
["source_id"] = targetID
})
					break;
				end
			end
		end)
		IEex_WriteDword(highestNumMatchesContainer + 0x5BA, 0)
		IEex_WriteByte(highestNumMatchesContainer + 0x863, 1)
		IEex_Eval('EquipMostDamagingMelee()',targetID)
	end
	ex_dead_pc_equipment_record[constantID] = nil
end

function MEREDIRE(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local spellTargetID = IEex_ReadDword(creatureData + 0x4BE)
	local sourceData = IEex_GetActorShare(sourceID)
	local action = IEex_ReadWord(creatureData + 0x476, 0x0)
	if action ~= 31 and action ~= 95 and action ~= 113 and action ~= 114 and action ~= 191 and action ~= 192 and action ~= 321 then return end
	if spellTargetID <= 0 then return end
	if IEex_CompareActorAllegiances(targetID, spellTargetID) == 1 then
		IEex_WriteDword(creatureData + 0x4BE, sourceID)
		IEex_WriteDword(creatureData + 0x540, IEex_ReadDword(sourceData + 0x6))
		IEex_WriteDword(creatureData + 0x544, IEex_ReadDword(sourceData + 0xA))
	else
		IEex_WriteDword(creatureData + 0x4BE, targetID)
		IEex_WriteDword(creatureData + 0x540, IEex_ReadDword(creatureData + 0x6))
		IEex_WriteDword(creatureData + 0x544, IEex_ReadDword(creatureData + 0xA))
	end
end

function MEGLOBEF(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
--	local player1ID = IEex_GetActorIDCharacter(0)
--	if not IEex_IsSprite(player1ID, true) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
--[[
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - IEex_ReadDword(effectData + 0x68)) / 15)
	end
--]]
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local special = IEex_ReadDword(effectData + 0x44)
	local casterlvl = IEex_ReadByte(effectData + 0xC4, 0)
--[[
	if spellRES == "" then
		for i = 0, 30, 1 do
			if 2 ^ i == special then
				spellRES = "MEGLOB" .. i
			end
		end
	end
--]]
	if bit.band(savingthrow, 0x10000) == 0 then
		if timing ~= 4096 then return end
		IEex_SetGlobalEffectFlags(special, duration)
--[[
		IEex_ApplyEffectToActor(player1ID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter2"] = 230,
["special"] = special,
["resource"] = IEex_ReadLString(effectData + 0x90, 8),
["parent_resource"] = spellRES,
["casterlvl"] = casterlvl,
["internal_flags"] = bit.bor(bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)), 0x10000000),
["source_target"] = player1ID,
["source_id"] = sourceID,
})
--]]
	else
		IEex_SetGlobalEffectFlags(special, 0)
--[[
		IEex_IterateActorEffects(player1ID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thespecial = IEex_ReadDword(eData + 0x48)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theopcode == 288 and theparameter2 == 230 and thespecial == special and theparent_resource == spellRES then
				IEex_WriteDword(eData + 0x114, 1)
			end
		end)
--]]
	end
end

function MEDRAGPR(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local special = IEex_ReadDword(effectData + 0x44)
	local timeSlowed = IEex_CheckGlobalEffect(0x2)
	if timeSlowed and ex_time_slow_speed_divisor == 0x7FFFFFFF then return end
	IEex_IterateProjectiles(targetID, special, function(share)
		if IEex_ReadDword(share + 0x72) == sourceID then
			local targetX = IEex_ReadDword(creatureData + 0x6)
			local targetY = IEex_ReadDword(creatureData + 0xA)
			IEex_WriteDword(share + 0x6, targetX)
			IEex_WriteDword(share + 0xA, targetY)
			IEex_WriteDword(share + 0xC8, targetX)
			IEex_WriteDword(share + 0xCC, targetY)
		end
	end)
end

ex_projectile_animation_position_adjust = {["BBARRH1"] = {0, 1, 0}, ["BBARRH2"] = {0, -100, 0}, ["COBONH1"] = {0, 1, 0}, ["COBONH2"] = {0, -100, 0}, }
function MEDRAGPA(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local animationRES = IEex_ReadLString(effectData + 0x18, 8)
	local timeSlowed = IEex_CheckGlobalEffect(0x2)
	if timeSlowed and ex_time_slow_speed_divisor == 0x7FFFFFFF then return end
	local internalFlags = IEex_ReadDword(effectData + 0xCC)
	IEex_IterateProjectiles(targetID, 0, function(share)
		local projectileAnimationData = IEex_ReadDword(share + 0x192)
		if projectileAnimationData > 0 and IEex_ReadLString(projectileAnimationData + 0xAC, 8) == animationRES then
			local projectileSourceID = IEex_ReadDword(share + 0x72)
			if (projectileSourceID == 0 and bit.band(internalFlags, 0x10) == 0) or projectileSourceID == sourceID then
				internalFlags = bit.bor(internalFlags, 0x10)
				IEex_WriteDword(effectData + 0xCC, internalFlags)
				IEex_WriteDword(share + 0x72, sourceID)
				local targetX = IEex_ReadDword(creatureData + 0x6)
				local targetY = IEex_ReadDword(creatureData + 0xA)
				local adjustX = 0
				local adjustY = 0
				if ex_projectile_animation_position_adjust[animationRES] ~= nil then
					adjustX = ex_projectile_animation_position_adjust[animationRES][1]
					adjustY = ex_projectile_animation_position_adjust[animationRES][2]
				end
				IEex_WriteDword(share + 0x6, targetX + adjustX)
				IEex_WriteDword(share + 0xA, targetY + adjustY)
				IEex_WriteDword(share + 0x116, targetX + adjustX)
				IEex_WriteDword(share + 0x11A, targetY + adjustY)
			end
		end
	end)
end

function MERESTOR(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local baseStrength = IEex_ReadByte(creatureData + 0x802, 0x0)
	local baseDexterity = IEex_ReadByte(creatureData + 0x805, 0x0)
	local baseConstitution = IEex_ReadByte(creatureData + 0x806, 0x0)
	local baseIntelligence = IEex_ReadByte(creatureData + 0x803, 0x0)
	local baseWisdom = IEex_ReadByte(creatureData + 0x804, 0x0)
	local baseCharisma = IEex_ReadByte(creatureData + 0x807, 0x0)
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter1 = IEex_ReadDword(eData + 0x1C)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thetiming = IEex_ReadDword(eData + 0x24)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		if thetiming ~= 2 and bit.band(thesavingthrow, 0x4000000) == 0 then
			if (theopcode == 44 and ((theparameter2 == 0 and theparameter1 < 0) or (theparameter2 == 1 and theparameter1 < baseStrength) or (theparameter2 == 2 and theparameter1 < 100)))
			or (theopcode == 15 and ((theparameter2 == 0 and theparameter1 < 0) or (theparameter2 == 1 and theparameter1 < baseDexterity) or (theparameter2 == 2 and theparameter1 < 100)))
			or (theopcode == 10 and ((theparameter2 == 0 and theparameter1 < 0) or (theparameter2 == 1 and theparameter1 < baseConstitution) or (theparameter2 == 2 and theparameter1 < 100)))
			or (theopcode == 19 and ((theparameter2 == 0 and theparameter1 < 0) or (theparameter2 == 1 and theparameter1 < baseIntelligence) or (theparameter2 == 2 and theparameter1 < 100)))
			or (theopcode == 49 and ((theparameter2 == 0 and theparameter1 < 0) or (theparameter2 == 1 and theparameter1 < baseWisdom) or (theparameter2 == 2 and theparameter1 < 100)))
			or (theopcode == 6 and ((theparameter2 == 0 and theparameter1 < 0) or (theparameter2 == 1 and theparameter1 < baseCharisma) or (theparameter2 == 2 and theparameter1 < 100)))
			or (theopcode == 78 and ((theparameter2 >= 4 and theparameter2 <= 9) or theparameter2 == 13 or theparameter2 == 14)) or (theopcode == 500 and theresource == "MEMODSTA" and theparameter1 < 0 and thespecial >= 36 and thespecial <= 42) or (theopcode == 142 and (theparameter2 == 90 or theparameter2 == 123)) then
				IEex_WriteDword(eData + 0x24, 4096)
				IEex_WriteDword(eData + 0x28, IEex_GetGameTick())
				IEex_WriteDword(eData + 0x114, 1)
			end
		end
	end)
end

function MEMODDUR(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local condition = IEex_ReadDword(effectData + 0x44)
	if bit.band(savingthrow, 0x200000) > 0 and parameter2 == 0 and parameter1 < 0 then
		local castCounter = IEex_ReadSignedWord(creatureData + 0x54E8, 0x0)
		if castCounter > -1 then
			IEex_WriteWord(creatureData + 0x54E8, castCounter - parameter1)
		end
		local destinationX, destinationY = IEex_GetActorDestination(targetID)
		if destinationX > 0 and destinationY > 0 then
			IEex_PreventMovingAttacksOfOpportunity(targetID, 10)
			IEex_JumpActorToPoint(targetID, destinationX, destinationY, true)
		end
	end
	if bit.band(savingthrow, 0x100000) == 0 then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thetiming = IEex_ReadDword(eData + 0x24)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local theresourceflags = IEex_ReadDword(eData + 0x9C)
			local theinternalflags = IEex_ReadDword(eData + 0xD8)
			if thetiming ~= 2 and (bit.band(savingthrow, 0x10000) == 0 or bit.band(theinternalflags, 0x4000) == 0) then
				if condition == 0 or (condition == 1 and (bit.band(theresourceflags, 0x400) > 0 or theopcode == 12)) or (condition == 2 and (bit.band(theresourceflags, 0x400) == 0 and theopcode ~= 12)) then
					IEex_WriteDword(eData + 0xD8, bit.bor(theinternalflags, 0x4000))
					local theduration = IEex_ReadDword(eData + 0x28)
					local thetime_applied = IEex_ReadDword(eData + 0x6C)
					if parameter2 == 0 then
						IEex_WriteDword(eData + 0x28, theduration + parameter1)
					elseif parameter2 == 1 then
						IEex_WriteDword(eData + 0x28, theduration + parameter1)
					elseif parameter2 == 2 then
						IEex_WriteDword(eData + 0x28, thetime_applied + math.floor((theduration - thetime_applied) * parameter1 / 100))
					end
				end
			end
		end)
	else
		for bt = 0, 30, 1 do
			local globalEffectExpiration = ex_global_effect_timers[bt + 1]
			if globalEffectExpiration > 0 then
				ex_global_effect_timers[bt + 1] = globalEffectExpiration + parameter1
				IEex_SetGlobal("EX_GLOBEF" .. bt, globalEffectExpiration + parameter1)
			end
		end
		local areaData = IEex_ReadDword(creatureData + 0x12)
		if areaData > 0 then
			local areaRES = IEex_ReadLString(areaData, 8)
			IEex_IterateIDs(areaData, 0x31, function(currentID)
				local currentShare = IEex_GetActorShare(currentID)
				local scriptName = IEex_ReadLString(currentShare + 0x554, 32)
				if scriptName == areaRES .. "AREAGL" then
					IEex_IterateActorEffects(currentID, function(eData)
						local theopcode = IEex_ReadDword(eData + 0x10)
						local theparameter1 = IEex_ReadDword(eData + 0x1C)
						local theparameter2 = IEex_ReadDword(eData + 0x20)
						local thetiming = IEex_ReadDword(eData + 0x24)
						local thesavingthrow = IEex_ReadDword(eData + 0x40)
						local theresource = IEex_ReadLString(eData + 0x30, 8)
						local theresourceflags = IEex_ReadDword(eData + 0x9C)
						local theinternalflags = IEex_ReadDword(eData + 0xD8)
						if thetiming ~= 2 and (bit.band(savingthrow, 0x10000) == 0 or bit.band(theinternalflags, 0x4000) == 0) then
							if condition == 0 or (condition == 1 and (bit.band(theresourceflags, 0x400) > 0 or theopcode == 12)) or (condition == 2 and (bit.band(theresourceflags, 0x400) == 0 and theopcode ~= 12)) then
								IEex_WriteDword(eData + 0xD8, bit.bor(theinternalflags, 0x4000))
								local theduration = IEex_ReadDword(eData + 0x28)
								local thetime_applied = IEex_ReadDword(eData + 0x6C)
								if parameter2 == 0 then
									IEex_WriteDword(eData + 0x28, theduration + parameter1)
								elseif parameter2 == 1 then
									IEex_WriteDword(eData + 0x28, theduration + parameter1)
								elseif parameter2 == 2 then
									IEex_WriteDword(eData + 0x28, thetime_applied + math.floor((theduration - thetime_applied) * parameter1 / 100))
								end
							end
						end
					end)
				end
			end)
		end
		if parameter2 == 0 and parameter1 < 0 then
			IEex_IterateProjectiles(targetID, -1, function(projectileData)
				local projectileType = IEex_ProjectileType[IEex_ReadWord(projectileData + 0x6E, 0x0) + 1]
				if projectileType == 6 then
					local remainingDuration = IEex_ReadSignedWord(projectileData + 0x4C0, 0x0)
					remainingDuration = remainingDuration + parameter1
					if remainingDuration <= 0 then
						remainingDuration = 1
					end
					IEex_WriteWord(projectileData + 0x4C0, remainingDuration)
				elseif projectileType == 11 then
					
					local remainingDuration = IEex_ReadSignedWord(projectileData + 0x2AE, 0x0)
					remainingDuration = remainingDuration + parameter1
					if remainingDuration <= 0 then
						remainingDuration = 1
					end
					IEex_WriteWord(projectileData + 0x2AE, remainingDuration)
				end
				IEex_WriteWord(projectileData + 0x70, 1000)
			end)
		end

		IEex_IterateTemporals(targetID, function(temporalData)
			local remainingDuration = IEex_ReadSignedWord(temporalData + 0x9C, 0x0)
			local elapsedDuration = IEex_ReadSignedWord(temporalData + 0x10E, 0x0)
			if parameter2 == 0 then
				local newRemainingDuration = remainingDuration + parameter1
				if newRemainingDuration <= 0 then
					newRemainingDuration = 1
				end
				if parameter1 < 0 then
					elapsedDuration = elapsedDuration + remainingDuration - newRemainingDuration
				end
				IEex_WriteWord(temporalData + 0x9C, newRemainingDuration)
				IEex_WriteWord(temporalData + 0x10E, elapsedDuration)
			end
		end)

	end

end

function MEHIDECR(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local special = IEex_ReadDword(effectData + 0x44)
	IEex_WriteByte(creatureData + 0x838, special)
end

ex_monk_animation_conversion = {[0x6000] = 0x6500, [0x6005] = 0x6500, [0x6100] = 0x6500, [0x6105] = 0x6500, [0x6200] = 0x6500, [0x6205] = 0x6500, [0x6300] = 0x6500, [0x6305] = 0x6500, [0x6010] = 0x6510, [0x6015] = 0x6510, [0x6110] = 0x6510, [0x6115] = 0x6510, [0x6210] = 0x6510, [0x6215] = 0x6510, [0x6310] = 0x6510, [0x6315] = 0x6510, }
function MEMONKAN(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	if IEex_IsGamePaused() then
		if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MEMONKAN", 5) then return end
	else
		if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MEMONKAN", 2) then return end
	end
	local special = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local baseAnimation = IEex_ReadDword(creatureData + 0x5C4)
	if special == 0 or special == 2 then
		local shieldRES = IEex_GetItemSlotRES(targetID, 44 + IEex_ReadByte(creatureData + 0x4C68, 0x0) * 2)
		if shieldRES ~= "" then
			local resWrapper = IEex_DemandRes(shieldRES, "ITM")
			local itemData = resWrapper:getData()
			local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
			local equippedAnimation = IEex_ReadLString(itemData + 0x22, 2)
			if (itemType == 41 or itemType == 47 or itemType == 49 or itemType == 53) and equippedAnimation ~= "  " then
				resWrapper:free()
				return
			end
		end
		if ex_monk_animation_conversion[baseAnimation] ~= nil and not IEex_GetActorSpellState(targetID, 188) then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = "USMONKAN",
["source_id"] = targetID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["parameter1"] = baseAnimation,
["parameter2"] = 188,
["savingthrow"] = 0x20000,
["parent_resource"] = "USMONKAN",
["source_id"] = targetID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 1,
["parameter1"] = ex_monk_animation_conversion[baseAnimation],
["parameter2"] = 2,
["parent_resource"] = "USMONKAN",
["source_id"] = targetID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = ex_monk_animation_conversion[baseAnimation],
["parameter2"] = 0,
["parent_resource"] = "USMONKAN",
["source_id"] = targetID
})
		end
--[[
		if special == 0 then
			if ex_monk_animation_conversion[baseAnimation] ~= nil or baseAnimation == 0x6500 or baseAnimation == 0x6510 then
				if IEex_GetItemSlotRES(targetID, 10) ~= IEex_GetItemSlotRES(targetID, 43) and string.sub(IEex_GetItemSlotRES(targetID, 10), 1, 7) ~= "00MFIST" then
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 43,
["resource"] = IEex_GetItemSlotRES(targetID, 10),
["parent_resource"] = "USMONKAN",
["source_id"] = targetID
})

				end
				if IEex_ReadByte(creatureData + 0x4BA4, 0x0) == 10 then
	--				IEex_Eval('SelectWeaponAbility(43,0)',targetID)
					IEex_Eval('EquipMostDamagingMelee()',targetID)
					IEex_WriteByte(creatureData + 0x3448, 43)
					IEex_WriteByte(creatureData + 0x4BA4, 43)
					IEex_WriteByte(creatureData + 0x569E, 43)
				end
			end



		end
--]]
	elseif special == 1 and (baseAnimation == 0x6500 or baseAnimation == 0x6510) then
		local oldAnimation = 0
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 188 and bit.band(thesavingthrow, 0x20000) > 0 then
				oldAnimation = IEex_ReadDword(eData + 0x1C)
			end
		end)
		if oldAnimation > 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = "USMONKAN",
["source_id"] = targetID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 1,
["parameter1"] = oldAnimation,
["parameter2"] = 2,
["parent_resource"] = "USMONKAN",
["source_id"] = targetID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = oldAnimation,
["parameter2"] = 0,
["parent_resource"] = "USMONKAN",
["source_id"] = targetID
})
		end
	end
end

ex_animation_vidcells = {
[0x5000] = {0x41C, 0x4F6, 0x5D0, 0x6AA, 0x784, 0x88E, 0x968, 0xA42, 0xB1C, 0xC26, 0xD00, 0xDDA, 0xEB4, 0xFBE, 0x1098, 0x1172, 0x124C, 0x1326},
[0x7000] = {0x40E, 0x4E8, 0x5C2, 0x69C},
[0x7F00] = {0x40A, 0x4E4},
[0x8000] = {0x40E, 0x4E8, 0x5C2, 0x69C, 0x7A6, 0x880, 0x95A, 0xA34},
[0xE000] = {0x40E, 0x4E8, 0x5C2, 0x69C, 0x776, 0x850, 0x92A, 0xA04, 0xADE, 0xBB8, 0xC92, 0xD6C, 0xE46, 0xF20, 0xFFA, 0x10D4, 0x11AE, 0x1288, 0x1362, 0x143C, 0x1516, 0x15F0, 0x16CA, 0x17A4, 0x187E, 0x1958, 0x1A32, 0x1B0C},
[0xF000] = {0x40E, 0x4E8, 0x5C2, 0x69C, 0x776, 0x850, 0x92A, 0xA04, 0xADE, 0xBB8, 0xC92, 0xD6C, 0xE46, 0xF20, 0xFFA, 0x10D4, 0x11AE, 0x1288, 0x1362, 0x143C, 0x1516, 0x15F0, 0x16CA, 0x17A4, 0x187E, 0x1958, 0x1A32, 0x1B0C, 0x1C16, 0x1CF0, 0x1DCA, 0x1EA4, 0x1F7E, 0x2058, 0x2132, 0x220C, 0x22E6, 0x23C0, 0x249A, 0x2574, 0x264E, 0x2728, 0x2802, 0x28DC, 0x29B6, 0x2A90, 0x2B6A, 0x2C44, 0x2D1E, 0x2DF8, 0x2ED2, 0x2FAC, 0x3086, 0x3160, 0x323A, 0x3314},
}
ex_animation_size = {[61395] = {48, 5, 7, }, [57976] = {48, 5, 10, }, [25872] = {16, 3, 9, }, [29696] = {16, 3, 8, }, [29952] = {16, 3, 6, }, [59545] = {36, 5, 7, }, [61213] = {24, 3, 7, }, [60313] = {24, 3, 7, }, [58504] = {24, 3, 11, }, [24848] = {16, 3, 9, }, [28672] = {16, 3, 7, }, [24592] = {16, 3, 9, }, [61411] = {12, 3, 7, }, [58248] = {16, 3, 4, }, [29184] = {24, 3, 10, }, [25104] = {16, 3, 9, }, [20739] = {16, 3, 9, }, [24852] = {16, 3, 9, }, [29473] = {16, 3, 7, }, [20483] = {16, 3, 9, }, [24596] = {16, 3, 9, }, [59528] = {24, 3, 7, }, [21251] = {16, 3, 9, }, [32256] = {24, 3, 10, }, [60329] = {24, 3, 7, }, [25108] = {16, 3, 9, }, [58520] = {16, 3, 7, }, [30976] = {24, 3, 2, }, [61427] = {64, 7, 7, }, [31232] = {24, 3, 5, }, [58008] = {24, 3, 7, }, [32516] = {36, 7, 13, }, [17920] = {16, 3, 0, }, [18176] = {16, 3, 0, }, [31236] = {24, 3, 5, }, [17408] = {16, 3, 0, }, [32520] = {24, 3, 4, }, [17664] = {16, 3, 0, }, [32553] = {16, 3, 9, }, [63384] = {16, 3, 7, }, [59337] = {24, 3, 7, }, [58280] = {24, 3, 4, }, [58924] = {24, 3, 7, }, [16384] = {16, 3, 0, }, [24835] = {16, 3, 9, }, [29456] = {24, 3, 10, }, [16640] = {16, 3, 0, }, [20755] = {16, 3, 9, }, [24579] = {16, 3, 9, }, [60427] = {36, 5, 9, }, [25347] = {16, 3, 9, }, [21267] = {16, 3, 9, }, [32528] = {16, 3, 10, }, [59320] = {24, 3, 9, }, [4610] = {72, 5, 14, }, [59353] = {16, 3, 7, }, [62731] = {48, 3, 7, }, [18432] = {16, 3, 0, }, [4096] = {36, 5, 8, }, [4097] = {36, 5, 8, }, [18192] = {16, 3, 0, }, [59609] = {24, 3, 7, }, [17424] = {16, 3, 0, }, [32536] = {24, 3, 8, }, [62491] = {24, 3, 7, }, [20736] = {16, 3, 9, }, [62747] = {48, 3, 7, }, [20480] = {16, 3, 9, }, [21248] = {16, 3, 9, }, [24851] = {16, 3, 9, }, [29472] = {24, 3, 10, }, [16656] = {16, 3, 0, }, [20992] = {16, 3, 9, }, [58386] = {16, 3, 7, }, [60459] = {24, 3, 7, }, [25363] = {16, 3, 9, }, [29187] = {24, 3, 10, }, [59592] = {28, 3, 7, }, [57362] = {16, 3, 7, }, [59385] = {24, 3, 7, }, [60467] = {48, 5, 7, }, [32515] = {16, 3, 11, }, [60401] = {16, 3, 7, }, [50688] = {16, 3, 6, }, [50944] = {16, 3, 5, }, [30979] = {24, 3, 2, }, [50432] = {16, 3, 8, }, [49664] = {12, 3, 10, }, [49920] = {12, 3, 4, }, [59641] = {16, 3, 7, }, [49152] = {16, 3, 8, }, [49408] = {12, 3, 4, }, [25602] = {16, 3, 9, }, [59368] = {24, 3, 7, }, [20752] = {16, 3, 9, }, [51712] = {16, 3, 6, }, [51968] = {16, 3, 6, }, [59244] = {24, 3, 7, }, [32523] = {28, 3, 15, }, [59426] = {16, 3, 7, }, [51456] = {16, 3, 6, }, [21264] = {16, 3, 9, }, [50704] = {16, 3, 6, }, [60681] = {24, 3, 7, }, [50960] = {16, 3, 5, }, [54272] = {16, 3, 8, }, [25346] = {16, 3, 9, }, [58418] = {16, 3, 7, }, [16641] = {16, 3, 0, }, [60491] = {24, 3, 7, }, [25090] = {16, 3, 9, }, [59624] = {28, 3, 7, }, [53248] = {16, 3, 8, }, [60392] = {16, 3, 7, }, [54016] = {16, 3, 8, }, [53760] = {16, 3, 8, }, [51728] = {16, 3, 6, }, [51216] = {16, 3, 5, }, [51472] = {16, 3, 6, }, [60697] = {24, 3, 7, }, [60507] = {24, 3, 7, }, [57344] = {24, 3, 7, }, [29698] = {16, 3, 8, }, [58376] = {16, 3, 7, }, [59144] = {24, 3, 7, }, [57608] = {48, 5, 7, }, [61465] = {16, 3, 5, }, [58120] = {16, 3, 7, }, [24850] = {16, 3, 9, }, [59458] = {16, 3, 7, }, [20481] = {16, 3, 9, }, [24594] = {16, 3, 9, }, [21249] = {16, 3, 9, }, [25362] = {16, 3, 9, }, [29186] = {24, 3, 10, }, [20993] = {16, 3, 9, }, [25106] = {16, 3, 9, }, [59400] = {16, 3, 7, }, [60168] = {24, 3, 7, }, [57938] = {36, 3, 7, }, [59160] = {24, 3, 7, }, [57624] = {48, 5, 7, }, [32514] = {36, 5, 8, }, [61481] = {16, 3, 15, }, [58136] = {16, 3, 7, }, [57880] = {36, 3, 7, }, [62216] = {48, 3, 5, }, [30978] = {24, 3, 2, }, [58268] = {16, 3, 4, }, [60952] = {24, 3, 7, }, [59672] = {16, 3, 7, }, [32518] = {16, 3, 11, }, [59416] = {16, 3, 7, }, [60184] = {24, 3, 7, }, [32551] = {16, 3, 9, }, [60217] = {36, 3, 7, }, [58664] = {36, 3, 7, }, [58408] = {16, 3, 7, }, [32768] = {24, 3, 5, }, [33024] = {16, 3, 5, }, [24833] = {16, 3, 9, }, [32548] = {16, 3, 9, }, [58153] = {16, 3, 7, }, [20753] = {16, 3, 9, }, [61976] = {24, 3, 6, }, [59936] = {24, 3, 7, }, [59553] = {16, 3, 7, }, [57929] = {24, 3, 7, }, [20497] = {16, 3, 9, }, [59577] = {16, 3, 7, }, [61726] = {24, 3, 5, }, [21265] = {16, 3, 9, }, [25089] = {16, 3, 9, }, [61710] = {16, 3, 5, }, [60337] = {24, 3, 0, }, [21009] = {16, 3, 9, }, [24837] = {16, 3, 9, }, [61224] = {24, 3, 13, }, [16642] = {16, 3, 0, }, [60200] = {24, 3, 7, }, [32559] = {16, 3, 9, }, [24581] = {16, 3, 9, }, [31491] = {16, 3, 15, }, [31488] = {16, 3, 15, }, [25349] = {16, 3, 9, }, [36864] = {24, 5, 6, }, [60712] = {24, 3, 7, }, [58457] = {16, 3, 7, }, [25093] = {16, 3, 9, }, [59225] = {24, 3, 7, }, [60365] = {24, 3, 7, }, [57656] = {48, 5, 7, }, [58217] = {16, 3, 7, }, [58201] = {16, 3, 7, }, [57400] = {16, 3, 7, }, [58168] = {16, 3, 3, }, [32257] = {24, 3, 10, }, [57912] = {36, 3, 7, }, [60936] = {24, 3, 7, }, [58299] = {16, 3, 4, }, [59192] = {24, 3, 7, }, [59176] = {24, 3, 7, }, [8960] = {24, 3, 7, }, [58441] = {16, 3, 7, }, [50176] = {12, 3, 4, }, [31235] = {24, 3, 5, }, [31234] = {24, 3, 5, }, [51200] = {16, 3, 5, }, [32531] = {24, 3, 13, }, [59448] = {16, 3, 7, }, [20498] = {16, 3, 9, }, [59481] = {16, 3, 7, }, [20737] = {16, 3, 9, }, [29953] = {16, 3, 6, }, [61448] = {16, 3, 5, }, [25603] = {16, 3, 9, }, [40960] = {24, 3, 8, }, [59656] = {16, 3, 7, }, [60241] = {16, 3, 5, }, [60376] = {16, 3, 7, }, [58489] = {16, 3, 7, }, [62475] = {24, 3, 7, }, [57424] = {64, 5, 9, }, [57672] = {36, 5, 7, }, [24849] = {16, 3, 9, }, [4609] = {72, 5, 14, }, [61347] = {16, 3, 7, }, [58184] = {16, 3, 3, }, [59512] = {24, 3, 7, }, [24593] = {16, 3, 9, }, [20482] = {16, 3, 9, }, [57961] = {24, 3, 7, }, [25361] = {16, 3, 9, }, [29185] = {24, 3, 10, }, [46592] = {16, 3, 0, }, [24595] = {16, 3, 9, }, [25105] = {16, 3, 9, }, [59249] = {16, 3, 7, }, [46080] = {16, 3, 0, }, [16402] = {16, 3, 0, }, [46336] = {16, 3, 0, }, [57416] = {64, 7, 7, }, [16658] = {16, 3, 0, }, [20994] = {16, 3, 9, }, [45824] = {16, 3, 0, }, [60265] = {16, 3, 5, }, [45056] = {24, 5, 0, }, [46096] = {16, 3, 0, }, [45312] = {24, 5, 0, }, [24853] = {16, 3, 9, }, [25345] = {16, 3, 9, }, [61264] = {16, 3, 0, }, [32513] = {16, 3, 8, }, [59688] = {16, 3, 7, }, [29442] = {36, 3, 10, }, [24580] = {16, 3, 9, }, [4608] = {72, 5, 14, }, [63370] = {16, 3, 7, }, [61363] = {24, 3, 7, }, [25605] = {16, 3, 9, }, [30977] = {24, 3, 2, }, [21008] = {16, 3, 9, }, [24578] = {16, 3, 9, }, [25088] = {16, 3, 9, }, [31233] = {24, 3, 5, }, [16896] = {16, 3, 0, }, [46608] = {16, 3, 0, }, [60233] = {16, 3, 7, }, [32517] = {16, 3, 11, }, [24834] = {16, 3, 9, }, [59265] = {16, 3, 7, }, [16386] = {16, 3, 0, }, [46352] = {16, 3, 0, }, [45568] = {16, 3, 0, }, [45584] = {16, 3, 0, }, [16400] = {16, 3, 0, }, [45840] = {16, 3, 0, }, [60281] = {16, 3, 5, }, [41216] = {24, 5, 6, }, [57378] = {16, 3, 7, }, [20496] = {16, 3, 9, }, [58472] = {24, 3, 11, }, [25856] = {16, 3, 9, }, [61280] = {16, 3, 0, }, [24832] = {16, 3, 9, }, [20738] = {16, 3, 9, }, [21250] = {16, 3, 9, }, [25109] = {16, 3, 9, }, [32554] = {24, 3, 5, }, [24576] = {16, 3, 9, }, [57448] = {24, 3, 7, }, [25360] = {16, 3, 9, }, [25344] = {16, 3, 9, }, [24597] = {16, 3, 9, }, [46848] = {16, 3, 0, }, [20754] = {16, 3, 9, }, [57993] = {24, 3, 7, }, [63354] = {16, 3, 7, }, [32522] = {28, 3, 15, }, [20499] = {16, 3, 9, }, [24836] = {16, 3, 9, }, [29697] = {16, 3, 8, }, [59281] = {16, 3, 7, }, [21266] = {16, 3, 9, }, [32558] = {36, 5, 9, }, [59496] = {24, 3, 7, }, [57896] = {36, 3, 7, }, [21010] = {16, 3, 9, }, [25348] = {16, 3, 9, }, [61197] = {24, 3, 7, }, [57690] = {36, 5, 7, }, [30208] = {16, 3, 6, }, [25092] = {16, 3, 9, }, [24577] = {16, 3, 9, }, [59308] = {24, 3, 7, }, [61296] = {16, 3, 0, }, [32519] = {24, 3, 13, }, [61379] = {36, 3, 7, }, [61329] = {16, 3, 10, }, [61961] = {24, 3, 6, }, [32562] = {24, 3, 9, }, [58653] = {36, 3, 7, }, }
ex_new_animation_size = {[58520] = {16, 3, 9, }, [59337] = {24, 3, 9, }, [59368] = {24, 3, 9, }, [60265] = {16, 3, 9, }, [60281] = {16, 3, 9, }, [60681] = {24, 3, 9, }, }

ex_modified_default_animations = {[57976] = true, }
function MEENLARG(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local animationData = IEex_ReadDword(creatureData + 0x50F0)
	local animationID = IEex_ReadWord(animationData + 0x4, 0x0)
	local animationSizeTable = ex_animation_size[animationID]
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if animationSizeTable ~= nil then
		local circleSize = animationSizeTable[1]
		local personalSpace = animationSizeTable[2]
		local movementScale = animationSizeTable[3]
		if IEex_ReadDword(animationData + 0x10) > 0 then
			IEex_WriteDword(animationData + 0x8, circleSize * -2)
			IEex_WriteDword(animationData + 0xC, math.floor(circleSize * 3 / 4) * -2)
			IEex_WriteDword(animationData + 0x10, circleSize * 2)
			IEex_WriteDword(animationData + 0x14, math.floor(circleSize * 3 / 4) * 2)
		end
		if IEex_ReadByte(animationData + 0x3E4, 0x0) > 0 and bit.band(savingthrow, 0x100000) == 0 then
			IEex_WriteByte(animationData + 0x3E4, personalSpace + 1)
		end
		if movementScale * 2 <= 255 then
			IEex_WriteByte(animationData + 0x6, movementScale * 2)
		end
	end


	if IEex_Helper_GetBridge("IEex_EnlargedAnimation", targetID) ~= animationID then
		IEex_Helper_SetBridge("IEex_EnlargedAnimation", targetID, animationID)
--[[
		IEex_WriteByte(animationData + 0x6, IEex_ReadByte(animationData + 0x6, 0x0) * 2)
		IEex_WriteDword(animationData + 0x8, IEex_ReadDword(animationData + 0x8) * 2)
		IEex_WriteDword(animationData + 0xC, IEex_ReadDword(animationData + 0xC) * 2)
		IEex_WriteDword(animationData + 0x10, IEex_ReadDword(animationData + 0x10) * 2)
		IEex_WriteDword(animationData + 0x14, IEex_ReadDword(animationData + 0x14) * 2)
		local personalSpace = IEex_ReadByte(animationData + 0x3E4, 0x0)
		if personalSpace > 0 then
			IEex_WriteByte(animationData + 0x3E4, personalSpace + 1)
		end
--]]
	end

--	IEex_WriteDword(creatureData + 0x740, bit.bor(IEex_ReadDword(creatureData + 0x740), 0x400))
	local vidcellList = {}
	if animationID >= 0x5000 and animationID <= 0x6FFF then
		vidcellList = ex_animation_vidcells[0x5000]
		IEex_WriteDword(animationData + 0x1444, 1)
	elseif animationID >= 0x7000 and animationID <= 0x7EFF then
		vidcellList = ex_animation_vidcells[0x7000]
	elseif animationID >= 0x7F00 and animationID <= 0x7FFF then
		vidcellList = ex_animation_vidcells[0x7F00]
	elseif animationID >= 0x8000 and animationID <= 0x8FFF then
		vidcellList = ex_animation_vidcells[0x8000]
	elseif animationID >= 0xE000 and animationID <= 0xEFFF then
		vidcellList = ex_animation_vidcells[0xE000]
	elseif animationID >= 0xF000 and animationID <= 0xFFFF then
		vidcellList = ex_animation_vidcells[0xF000]
	end
	if #vidcellList > 0 then
		for k, v in ipairs(vidcellList) do
			IEex_WriteDword(animationData + v + 0xD6, 1)
		end
	end
end

function IEex_ResetSize(creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local animationData = IEex_ReadDword(creatureData + 0x50F0)
	local animationID = IEex_ReadWord(animationData + 0x4, 0x0)
	if IEex_Helper_GetBridge("IEex_EnlargedAnimation", targetID) ~= nil or ex_modified_default_animations[animationID] ~= nil then
		IEex_Helper_EraseBridgeKey("IEex_EnlargedAnimation", targetID)

		local animationSizeTable = ex_animation_size[animationID]
		if animationSizeTable ~= nil then
			local circleSize = animationSizeTable[1]
			local personalSpace = animationSizeTable[2]
			local movementScale = animationSizeTable[3]
			if IEex_ReadDword(animationData + 0x10) > 0 then
				IEex_WriteDword(animationData + 0x8, circleSize * -1)
				IEex_WriteDword(animationData + 0xC, math.floor(circleSize * 3 / 4) * -1)
				IEex_WriteDword(animationData + 0x10, circleSize)
				IEex_WriteDword(animationData + 0x14, math.floor(circleSize * 3 / 4))
			end
			if IEex_ReadByte(animationData + 0x3E4, 0x0) > 0 then
				IEex_WriteByte(animationData + 0x3E4, personalSpace)
			end
			if movementScale * 2 <= 255 then
				IEex_WriteByte(animationData + 0x6, movementScale)
			end
		end
--[[
		local extraFlags = IEex_ReadDword(creatureData + 0x740)
		if bit.band(extraFlags, 0x400) > 0 then
			IEex_WriteDword(creatureData + 0x740, bit.band(extraFlags, 0xFFFFFBFF))
			IEex_WriteByte(animationData + 0x6, math.floor(IEex_ReadByte(animationData + 0x6, 0x0) / 2))
			IEex_WriteDword(animationData + 0x8, math.floor(IEex_ReadDword(animationData + 0x8) / 2))
			IEex_WriteDword(animationData + 0xC, math.floor(IEex_ReadDword(animationData + 0xC) / 2))
			IEex_WriteDword(animationData + 0x10, math.floor(IEex_ReadDword(animationData + 0x10) / 2))
			IEex_WriteDword(animationData + 0x14, math.floor(IEex_ReadDword(animationData + 0x14) / 2))
			local personalSpace = IEex_ReadByte(animationData + 0x3E4, 0x0)
			if personalSpace > 3 then
				IEex_WriteByte(animationData + 0x3E4, personalSpace - 1)
			end
		end
--]]
		local vidcellList = {}
		if animationID >= 0x5000 and animationID <= 0x6FFF then
			vidcellList = ex_animation_vidcells[0x5000]
			IEex_WriteDword(animationData + 0x1444, 0)
		elseif animationID >= 0x7000 and animationID <= 0x7EFF then
			vidcellList = ex_animation_vidcells[0x7000]
		elseif animationID >= 0x7F00 and animationID <= 0x7FFF then
			vidcellList = ex_animation_vidcells[0x7F00]
		elseif animationID >= 0x8000 and animationID <= 0x8FFF then
			vidcellList = ex_animation_vidcells[0x8000]
		elseif animationID >= 0xE000 and animationID <= 0xEFFF then
			vidcellList = ex_animation_vidcells[0xE000]
		elseif animationID >= 0xF000 and animationID <= 0xFFFF then
			vidcellList = ex_animation_vidcells[0xF000]
		end
		if #vidcellList > 0 then
			for k, v in ipairs(vidcellList) do
				IEex_WriteDword(animationData + v + 0xD6, 0)
			end
		end
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 0,
["source_id"] = targetID
})
	end

end

function MECINVIS(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local animationData = IEex_ReadDword(creatureData + 0x50F0)
	local animationID = IEex_ReadWord(animationData + 0x4, 0x0)
	local animationSizeTable = ex_animation_size[animationID]
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if animationSizeTable ~= nil then
		local circleSize = animationSizeTable[1]
		local personalSpace = animationSizeTable[2]
		local movementScale = animationSizeTable[3]
		if IEex_ReadDword(animationData + 0x10) > 0 then
			IEex_WriteDword(animationData + 0x8, circleSize * -2)
			IEex_WriteDword(animationData + 0xC, math.floor(circleSize * 3 / 4) * -2)
			IEex_WriteDword(animationData + 0x10, circleSize * 2)
			IEex_WriteDword(animationData + 0x14, math.floor(circleSize * 3 / 4) * 2)
		end
		if IEex_ReadByte(animationData + 0x3E4, 0x0) > 0 and bit.band(savingthrow, 0x100000) == 0 then
			IEex_WriteByte(animationData + 0x3E4, personalSpace + 1)
		end
		if movementScale * 2 <= 255 then
			IEex_WriteByte(animationData + 0x6, movementScale * 2)
		end
	end


	if IEex_Helper_GetBridge("IEex_EnlargedAnimation", targetID) ~= animationID then
		IEex_Helper_SetBridge("IEex_EnlargedAnimation", targetID, animationID)
--[[
		IEex_WriteByte(animationData + 0x6, IEex_ReadByte(animationData + 0x6, 0x0) * 2)
		IEex_WriteDword(animationData + 0x8, IEex_ReadDword(animationData + 0x8) * 2)
		IEex_WriteDword(animationData + 0xC, IEex_ReadDword(animationData + 0xC) * 2)
		IEex_WriteDword(animationData + 0x10, IEex_ReadDword(animationData + 0x10) * 2)
		IEex_WriteDword(animationData + 0x14, IEex_ReadDword(animationData + 0x14) * 2)
		local personalSpace = IEex_ReadByte(animationData + 0x3E4, 0x0)
		if personalSpace > 0 then
			IEex_WriteByte(animationData + 0x3E4, personalSpace + 1)
		end
--]]
	end

--	IEex_WriteDword(creatureData + 0x740, bit.bor(IEex_ReadDword(creatureData + 0x740), 0x400))
	local vidcellList = {}
	if animationID >= 0x5000 and animationID <= 0x6FFF then
--		vidcellList = ex_animation_vidcells[0x5000]
		vidcellList = {0x41C, 0x4F6, 0x5D0, 0x6AA, 0x784}
--		IEex_WriteDword(animationData + 0x1444, 1)
	end
	if #vidcellList > 0 then
		for k, v in ipairs(vidcellList) do
--			IEex_WriteLString(animationData + v + 0xAC, "", 8)
			IEex_WriteWord(animationData + v + 0xC6, -1)
--			IEex_WriteDword(animationData + v + 0xD6, 1)
		end
	end
end

function IEex_Enlarge(actorID)
	if not IEex_IsSprite(actorID, true) then return end
	local share = IEex_GetActorShare(actorID)
	local animationData = IEex_ReadDword(share + 0x50F0)
	IEex_WriteDword(animationData + 0x4F2, 1)
	IEex_WriteDword(animationData + 0x5CC, 1)
	IEex_WriteDword(animationData + 0x6A6, 1)
	IEex_WriteDword(animationData + 0x780, 1)
	IEex_WriteDword(animationData + 0x85A, 1)
	IEex_WriteDword(animationData + 0x964, 1)
	IEex_WriteDword(animationData + 0xA3E, 1)
	IEex_WriteDword(animationData + 0xB18, 1)
	IEex_WriteDword(animationData + 0xBF2, 1)
	IEex_WriteDword(animationData + 0xCFC, 1)
	IEex_WriteDword(animationData + 0xDD6, 1)
	IEex_WriteDword(animationData + 0xEB0, 1)
	IEex_WriteDword(animationData + 0xF8A, 1)
	IEex_WriteDword(animationData + 0x1094, 1)
	IEex_WriteDword(animationData + 0x116E, 1)
	IEex_WriteDword(animationData + 0x1248, 1)
	IEex_WriteDword(animationData + 0x1322, 1)
	IEex_WriteDword(animationData + 0x13FC, 1)
	IEex_WriteDword(animationData + 0x1444, 1)
end

function MEDARKNE(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - time_applied) / 15)
	end
	local weaponRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local darkvisionLevel = 0
	local animation = IEex_ReadDword(creatureData + 0x5C4)
	local racePlusSub = IEex_ReadByte(creatureData + 0x26, 0x0) * 0x10000 + IEex_GetActorStat(targetID, 93)
	if ex_darkvision_animations[animation] ~= nil then
		darkvisionLevel = ex_darkvision_animations[animation]
	elseif ex_darkvision_races[racePlusSub] ~= nil then
		darkvisionLevel = ex_darkvision_races[racePlusSub]
	elseif IEex_GetActorState(targetID,0x20000) then
		darkvisionLevel = 1
	end
	local attackPenalty = ex_darkvision_attack_penalty[darkvisionLevel]
	if attackPenalty == -99 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 74,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
	elseif attackPenalty < 0 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 54,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter1"] = attackPenalty,
["savingthrow"] = 0x10000,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
	end

end

function MEDARKSP(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local state = IEex_ReadDword(effectData + 0x44)
	local doApply = false
	local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
	if bit.band(stateValue, 0x40000) ~= 0 then
		doApply = true
	else
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 54 and bit.band(thesavingthrow, 0x10000) > 0 then
				doApply = true
			end
		end)
	end
	local invert = (bit.band(IEex_ReadDword(effectData + 0x3C), 0x100000) > 0)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	if doApply then
		if invert == false then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if spellRES ~= "" then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterlvl,
["parent_resource"] = spellRES,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_id"] = sourceID
})
			end
		end
	else
		if invert == true then
			local spellRES = IEex_ReadLString(effectData + 0x18, 8)
			if spellRES ~= "" then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterlvl,
["parent_resource"] = spellRES,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_id"] = sourceID
})
			end
		end
	end
end

function MEPOLYMO(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	local sourceID = IEex_ReadDword(effectData + 0x10C)
--	if not IEex_IsSprite(sourceID, false) then return end
	local creRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local baseAnimation = IEex_ReadDword(creatureData + 0x5C4)
	local baseStrength = IEex_ReadByte(creatureData + 0x802, 0x0)
	local baseDexterity = IEex_ReadByte(creatureData + 0x805, 0x0)
	local baseConstitution = IEex_ReadByte(creatureData + 0x806, 0x0)
	local baseIntelligence = IEex_ReadByte(creatureData + 0x803, 0x0)
	local baseWisdom = IEex_ReadByte(creatureData + 0x804, 0x0)
	local baseCharisma = IEex_ReadByte(creatureData + 0x807, 0x0)
	local specialFlags = IEex_ReadByte(creatureData + 0x89F, 0x0)
	local baseCritImmunity = 0
	if bit.band(specialFlags, 0x2) > 0 then
		baseCritImmunity = 1
	end
	local hasCursedWeapon = false
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter1 = IEex_ReadDword(eData + 0x1C)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
		if theopcode == 288 and theparameter2 == 241 and thespecial >= 4 and bit.band(thesavingthrow, 0x100000) > 0 then
			hasCursedWeapon = true
		end
	end)
	if hasCursedWeapon then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 290,
["target"] = 2,
["timing"] = 0,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["source_id"] = targetID
})
		return
	end
	local oldAnimationDataFound = false
	if IEex_GetActorSpellState(targetID, 188) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 188 and bit.band(thesavingthrow, 0x20000) == 0 then
				oldAnimationDataFound = true
				baseAnimation = IEex_ReadDword(eData + 0x1C)
				baseStrength = IEex_ReadByte(eData + 0x44, 0x0)
				baseDexterity = IEex_ReadByte(eData + 0x45, 0x0)
				baseConstitution = IEex_ReadByte(eData + 0x46, 0x0)
				baseIntelligence = IEex_ReadByte(eData + 0x47, 0x0)
				baseWisdom = IEex_ReadByte(eData + 0x48, 0x0)
				baseCharisma = IEex_ReadByte(eData + 0x49, 0x0)
			end
		end)
	end
	if not oldAnimationDataFound then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["parameter1"] = baseAnimation,
["parameter2"] = 188,
["savingthrow"] = baseCritImmunity * 0x1000000,
["savebonus"] = baseStrength + baseDexterity * 0x100 + baseConstitution * 0x10000 + baseIntelligence * 0x1000000,
["special"] = baseWisdom + baseCharisma * 0x100,
["parent_resource"] = "USPOLYBA",
["source_id"] = targetID
})
	end
	local resWrapper = IEex_DemandRes(creRES, "CRE")
	if resWrapper:isValid() then
		local formData = resWrapper:getData()
		if bit.band(IEex_ReadByte(formData + 0x303, 0x0), 0x2) > 0 then
			IEex_WriteByte(creatureData + 0x89F, bit.bor(specialFlags, 0x2))
		else
			IEex_WriteByte(creatureData + 0x89F, bit.band(specialFlags, 0xFD))
		end
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = "USPOLYSP",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = "USPOLYMO",
["source_id"] = targetID
})
		local newStrength = IEex_ReadByte(formData + 0x266, 0x0)
		if newStrength > baseStrength then
--			IEex_WriteByte(creatureData + 0x802, newStrength)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 44,
["target"] = 2,
["timing"] = 9,
["parameter1"] = newStrength,
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		else
--			IEex_WriteByte(creatureData + 0x802, baseStrength)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 44,
["target"] = 2,
["timing"] = 9,
["parameter1"] = baseStrength,
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		end
		local newDexterity = IEex_ReadByte(formData + 0x269, 0x0)
		if newDexterity > baseDexterity then
--			IEex_WriteByte(creatureData + 0x805, newDexterity)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 15,
["target"] = 2,
["timing"] = 9,
["parameter1"] = newDexterity,
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		else
--			IEex_WriteByte(creatureData + 0x805, baseDexterity)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 15,
["target"] = 2,
["timing"] = 9,
["parameter1"] = baseDexterity,
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		end
		local newConstitution = IEex_ReadByte(formData + 0x26A, 0x0)
		if newConstitution > baseConstitution then
--			IEex_WriteByte(creatureData + 0x806, newConstitution)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 10,
["target"] = 2,
["timing"] = 9,
["parameter1"] = newConstitution,
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		else
--			IEex_WriteByte(creatureData + 0x806, baseConstitution)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 10,
["target"] = 2,
["timing"] = 9,
["parameter1"] = baseConstitution,
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		end
--[[
		local newIntelligence = IEex_ReadByte(formData + 0x267, 0x0)
		if newIntelligence > baseIntelligence then
--			IEex_WriteByte(creatureData + 0x803, newIntelligence)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 19,
["target"] = 2,
["timing"] = 9,
["parameter1"] = newIntelligence,
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		else
--			IEex_WriteByte(creatureData + 0x803, baseIntelligence)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 19,
["target"] = 2,
["timing"] = 9,
["parameter1"] = baseIntelligence,
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		end
		local newWisdom = IEex_ReadByte(formData + 0x268, 0x0)
		if newWisdom > baseWisdom then
--			IEex_WriteByte(creatureData + 0x804, newWisdom)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 49,
["target"] = 2,
["timing"] = 9,
["parameter1"] = newWisdom,
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		else
--			IEex_WriteByte(creatureData + 0x804, baseWisdom)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 49,
["target"] = 2,
["timing"] = 9,
["parameter1"] = baseWisdom,
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		end
		local newCharisma = IEex_ReadByte(formData + 0x26B, 0x0)
		if newCharisma > baseCharisma then
--			IEex_WriteByte(creatureData + 0x807, newCharisma)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 6,
["target"] = 2,
["timing"] = 9,
["parameter1"] = newCharisma,
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		else
--			IEex_WriteByte(creatureData + 0x807, baseCharisma)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 6,
["target"] = 2,
["timing"] = 9,
["parameter1"] = baseCharisma,
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		end
--]]
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 144,
["target"] = 2,
["timing"] = 9,
["parameter2"] = 2,
["parent_resource"] = "USPOLYSP",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 145,
["target"] = 2,
["timing"] = 9,
["parameter2"] = 1,
["parent_resource"] = "USPOLYSP",
["source_id"] = targetID
})
		if bit.band(savingthrow, 0x200000) > 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["parameter1"] = -4,
["parameter2"] = 193,
["special"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		end
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 9,
["parameter1"] = IEex_ReadWord(formData + 0x46, 0x0) - 10,
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		if IEex_ReadSignedByte(formData + 0x51, 0x0) ~= -1 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 1,
["target"] = 2,
["timing"] = 9,
["parameter1"] = IEex_ReadSignedByte(formData + 0x51, 0x0),
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		end
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 30,
["target"] = 2,
["timing"] = 9,
["parameter1"] = IEex_ReadSignedByte(formData + 0x55, 0x0),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 28,
["target"] = 2,
["timing"] = 9,
["parameter1"] = IEex_ReadSignedByte(formData + 0x56, 0x0),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 29,
["target"] = 2,
["timing"] = 9,
["parameter1"] = IEex_ReadSignedByte(formData + 0x57, 0x0),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 27,
["target"] = 2,
["timing"] = 9,
["parameter1"] = IEex_ReadSignedByte(formData + 0x58, 0x0),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 166,
["target"] = 2,
["timing"] = 9,
["parameter1"] = IEex_ReadSignedByte(formData + 0x59, 0x0),
["parameter2"] = 1,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 86,
["target"] = 2,
["timing"] = 9,
["parameter1"] = IEex_ReadSignedByte(formData + 0x5C, 0x0),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 87,
["target"] = 2,
["timing"] = 9,
["parameter1"] = IEex_ReadSignedByte(formData + 0x5D, 0x0),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 88,
["target"] = 2,
["timing"] = 9,
["parameter1"] = IEex_ReadSignedByte(formData + 0x5E, 0x0),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 89,
["target"] = 2,
["timing"] = 9,
["parameter1"] = IEex_ReadSignedByte(formData + 0x5F, 0x0),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 31,
["target"] = 2,
["timing"] = 9,
["parameter1"] = IEex_ReadSignedByte(formData + 0x60, 0x0),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		if IEex_ReadWord(formData + 0x1BC, 0x0) > 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 436,
["target"] = 2,
["timing"] = 9,
["parameter2"] = IEex_ReadWord(formData + 0x1BC, 0x0),
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		end
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 1,
["parameter1"] = IEex_ReadDword(formData + 0x28),
["parameter2"] = 2,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter1"] = IEex_ReadDword(formData + 0x28),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
	end
	resWrapper:free()
end

function MEPOLYBA(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	local sourceID = IEex_ReadDword(effectData + 0x10C)
--	if not IEex_IsSprite(sourceID, false) then return end
	local baseAnimation = 0
--	local baseStrength = IEex_ReadByte(creatureData + 0x802, 0x0)
--	local baseDexterity = IEex_ReadByte(creatureData + 0x805, 0x0)
--	local baseConstitution = IEex_ReadByte(creatureData + 0x806, 0x0)
--	local baseIntelligence = IEex_ReadByte(creatureData + 0x803, 0x0)
--	local baseWisdom = IEex_ReadByte(creatureData + 0x804, 0x0)
--	local baseCharisma = IEex_ReadByte(creatureData + 0x807, 0x0)
	local specialFlags = IEex_ReadByte(creatureData + 0x89F, 0x0)
--	if IEex_GetActorSpellState(targetID, 188) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 188 and bit.band(thesavingthrow, 0x20000) == 0 then
				baseAnimation = IEex_ReadDword(eData + 0x1C)
--				baseStrength = IEex_ReadByte(eData + 0x44, 0x0)
--				baseDexterity = IEex_ReadByte(eData + 0x45, 0x0)
--				baseConstitution = IEex_ReadByte(eData + 0x46, 0x0)
--				baseIntelligence = IEex_ReadByte(eData + 0x47, 0x0)
--				baseWisdom = IEex_ReadByte(eData + 0x48, 0x0)
--				baseCharisma = IEex_ReadByte(eData + 0x49, 0x0)
				if bit.band(thesavingthrow, 0x1000000) > 0 then
					IEex_WriteByte(creatureData + 0x89F, bit.bor(specialFlags, 0x2))
				else
					IEex_WriteByte(creatureData + 0x89F, bit.band(specialFlags, 0xFD))
				end
			end
		end)
--	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = "USPOLYSP",
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = "USPOLYMO",
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = "USPOLYBA",
["source_id"] = targetID
})
	if baseAnimation > 0 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 1,
["parameter1"] = baseAnimation,
["parameter2"] = 2,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter1"] = baseAnimation,
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 276,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 112,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 276,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 255,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
	end
end

function MEOFFANI(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	local baseAnimation = IEex_ReadDword(creatureData + 0x5C4)
	local weaponSet = IEex_ReadByte(creatureData + 0x4C68, 0x0)
	local slotData = IEex_ReadDword(creatureData + 0x4B88 + weaponSet * 0x8)
	local shieldRES = ""
	if slotData > 0 then
		shieldRES = IEex_ReadLString(slotData + 0xC, 8)
	end
	local oldAnimationDataFound = false
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
		if shieldRES ~= "" and theparent_resource == shieldRES then
			IEex_WriteDword(eData + 0x114, 1)
		elseif theopcode == 288 and theparameter2 == 188 and bit.band(thesavingthrow, 0x20000) == 0 then
			oldAnimationDataFound = true
		end
	end)
	if shieldRES ~= "" then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 0,
["resource"] = shieldRES,
["source_id"] = sourceID
})
	end
	if not oldAnimationDataFound then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 1,
["parameter1"] = baseAnimation,
["parameter2"] = 2,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter1"] = baseAnimation,
["parameter2"] = 0,
["source_id"] = sourceID
})
	end
end

function MEBASEAN(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	local baseAnimation = IEex_ReadDword(creatureData + 0x5C4)
	local newAnimation = IEex_ReadDword(effectData + 0x18)
	if newAnimation < 0 then return end
	if baseAnimation ~= newAnimation then
		local oldAnimationDataFound = false
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 188 and bit.band(thesavingthrow, 0x20000) == 0 then
				oldAnimationDataFound = true
			end
		end)
		if not oldAnimationDataFound then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 1,
["parameter1"] = newAnimation,
["parameter2"] = 2,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter1"] = newAnimation,
["parameter2"] = 0,
["source_id"] = sourceID
})
		end
	end
end

function MEBASEAM(effectData, creatureData)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	local summonerID = IEex_GetActorSummonerID(sourceID)
	if summonerID <= 0 then return end
	local newAnimation = IEex_ReadDword(effectData + 0x18)
	IEex_IterateActorEffects(summonerID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		if theopcode == 500 and theresource == "MEBASEAN" then
			IEex_WriteDword(eData + 0x1C, newAnimation)
		end
	end)
end

ex_moonblade_items = {["00SWDL09"] = true, ["USHFSL09"] = true, }
function MEMOONBL(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local weaponRES = IEex_ReadLString(effectData + 0x18, 8)
	local special = IEex_ReadDword(effectData + 0x44)
	local equippedSlot = IEex_ReadByte(creatureData + 0x4BA4, 0x0)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if ex_moonblade_items[IEex_GetItemSlotRES(targetID, equippedSlot)] ~= nil then
		IEex_WriteDword(creatureData + 0xA00, IEex_ReadDword(creatureData + 0xA00) + special)
		IEex_WriteByte(creatureData + 0x9F8, IEex_ReadSignedByte(creatureData + 0x9F8, 0x0) + special)
	elseif equippedSlot >= 43 and equippedSlot <= 49 and ex_moonblade_items[IEex_GetItemSlotRES(targetID, equippedSlot + 1)] ~= nil then
		IEex_WriteDword(creatureData + 0xA04, IEex_ReadDword(creatureData + 0xA04) + special)
		IEex_WriteByte(creatureData + 0x9FC, IEex_ReadSignedByte(creatureData + 0x9FC, 0x0) + special)
	elseif bit.band(internalFlags, 0x10) == 0 then
		IEex_WriteDword(effectData + 0xD4, bit.bor(internalFlags, 0x10))
		local timing = IEex_ReadDword(effectData + 0x20)
		local duration = IEex_ReadDword(effectData + 0x24)
		local time_applied = IEex_ReadDword(effectData + 0x68)
		if timing == 4096 then
			timing = 0
			duration = math.floor((duration - time_applied) / 15)
		end
		IEex_WriteDword(effectData + 0x110, 1)
--[[
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 111,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["resource"] = weaponRES,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xD4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
--]]
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter1"] = IEex_ReadDword(effectData + 0x18),
["parameter2"] = IEex_ReadDword(effectData + 0x1C),
["resource"] = "MERNWEAP",
["savingthrow"] = savingthrow,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
	end
	IEex_WriteDword(effectData + 0xD4, bit.bor(internalFlags, 0x10))
end

function MEWEPENC(effectData, creatureData)
	if true then return end
end

function MEWEPFLG(effectData, creatureData)
	if true then return end
end

function MEDAMWEP(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local weaponRES = IEex_ReadLString(effectData + 0x18, 8)
	local damageBonus = IEex_ReadDword(effectData + 0x44)
	local equippedSlot = IEex_ReadByte(creatureData + 0x4BA4, 0x0)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if bit.band(savingthrow, 0x10000) > 0 then
		local bonusStat = IEex_ReadByte(effectData + 0x44, 0x0)
		local bonusStatMultiplier = IEex_ReadByte(effectData + 0x45, 0x0)
		local bonusStatDivisor = IEex_ReadByte(effectData + 0x46, 0x0)
		if bonusStatMultiplier == 0 then
			bonusStatMultiplier = 1
		end
		if bonusStatDivisor == 0 then
			bonusStatDivisor = 1
		end
		local bonusStatValue = IEex_GetActorStat(targetID, bonusStat)
		if bonusStat >= 36 and bonusStat <= 42 then
			bonusStatValue = math.floor((bonusStatValue - 10) / 2)
		end
		bonusStatValue = math.floor(bonusStatValue * bonusStatMultiplier / bonusStatDivisor)
		if bit.band(savingthrow, 0x20000) > 0 then
			local strengthBonus = math.floor((IEex_GetActorStat(targetID, 36) - 10) / 2)
			local weaponWrapper = IEex_DemandRes(weaponRES, "ITM")
			if weaponWrapper:isValid() then
				local itemData = weaponWrapper:getData()
				local itemFlags = IEex_ReadDword(itemData + 0x18)
				if bit.band(itemFlags, 0x2) > 0 then
					strengthBonus = math.floor(strengthBonus * 1.5)
				end
			end
			weaponWrapper:free()
			bonusStatValue = bonusStatValue - strengthBonus
			if bonusStatValue < 0 then
				bonusStatValue = 0
			end
		end
		damageBonus = bonusStatValue
	end
	if equippedSlot >= 43 and equippedSlot <= 49 and ((IEex_GetItemSlotRES(targetID, equippedSlot) == weaponRES and IEex_GetItemSlotRES(targetID, equippedSlot + 1) == weaponRES) or (weaponRES == "" and bit.band(savingthrow, 0x40000) > 0)) then
		if bit.band(savingthrow, 0x40000) == 0 then
--[[
			local numExtraEffects = 0
			IEex_IterateActorEffects(targetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theweaponRES = IEex_ReadLString(eData + 0x1C, 8)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				if theopcode == 500 and theweaponRES == weaponRES and theresource == "MEDAMWEP" and eData + 0x4 ~= effectData then
					numExtraEffects = numExtraEffects + 1
				end
			end)
			if numExtraEffects % 2 == 0 then
				if bit.band(savingthrow, 0x100000) == 0 then
					IEex_WriteDword(creatureData + 0xA00, IEex_ReadDword(creatureData + 0xA00) + damageBonus)
				end
				if bit.band(savingthrow, 0x200000) == 0 then
					IEex_WriteByte(creatureData + 0x9F8, IEex_ReadSignedByte(creatureData + 0x9F8, 0x0) + damageBonus)
				end
			else
				if bit.band(savingthrow, 0x100000) == 0 then
					IEex_WriteDword(creatureData + 0xA04, IEex_ReadDword(creatureData + 0xA04) + damageBonus)
				end
				if bit.band(savingthrow, 0x200000) == 0 then
					IEex_WriteByte(creatureData + 0x9FC, IEex_ReadSignedByte(creatureData + 0x9FC, 0x0) + damageBonus)
				end
			end
--]]
			if bit.band(savingthrow, 0x100000) == 0 then
				IEex_WriteDword(creatureData + 0xA00, IEex_ReadDword(creatureData + 0xA00) + damageBonus)
			end
			if bit.band(savingthrow, 0x200000) == 0 then
				IEex_WriteByte(creatureData + 0x9F8, IEex_ReadSignedByte(creatureData + 0x9F8, 0x0) + damageBonus)
			end
		else
			if bit.band(savingthrow, 0x100000) == 0 then
				IEex_WriteDword(creatureData + 0xA00, IEex_ReadDword(creatureData + 0xA00) + damageBonus)
				IEex_WriteDword(creatureData + 0xA04, IEex_ReadDword(creatureData + 0xA04) + damageBonus)
			end
			if bit.band(savingthrow, 0x200000) == 0 then
				IEex_WriteByte(creatureData + 0x9F8, IEex_ReadSignedByte(creatureData + 0x9F8, 0x0) + damageBonus)
				IEex_WriteByte(creatureData + 0x9FC, IEex_ReadSignedByte(creatureData + 0x9FC, 0x0) + damageBonus)
			end
		end
	elseif IEex_GetItemSlotRES(targetID, equippedSlot) == weaponRES or weaponRES == "" then
		if bit.band(savingthrow, 0x100000) == 0 then
			IEex_WriteDword(creatureData + 0xA00, IEex_ReadDword(creatureData + 0xA00) + damageBonus)
		end
		if bit.band(savingthrow, 0x200000) == 0 then
			IEex_WriteByte(creatureData + 0x9F8, IEex_ReadSignedByte(creatureData + 0x9F8, 0x0) + damageBonus)
		end
	elseif equippedSlot >= 43 and equippedSlot <= 49 and IEex_GetItemSlotRES(targetID, equippedSlot + 1) == weaponRES then
		if bit.band(savingthrow, 0x100000) == 0 then
			IEex_WriteDword(creatureData + 0xA04, IEex_ReadDword(creatureData + 0xA04) + damageBonus)
		end
		if bit.band(savingthrow, 0x200000) == 0 then
			IEex_WriteByte(creatureData + 0x9FC, IEex_ReadSignedByte(creatureData + 0x9FC, 0x0) + damageBonus)
		end
	end
end

function MERNWEAP(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - time_applied) / 15)
	end
	local weaponRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if casterClass == 8 then
--[[
		if timing == 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 112,
["target"] = 2,
["timing"] = 4,
["duration"] = duration,
["resource"] = weaponRES,
["savingthrow"] = savingthrow,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 112,
["target"] = 2,
["timing"] = 4,
["duration"] = duration,
["resource"] = weaponRES,
["savingthrow"] = savingthrow,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 4,
["duration"] = duration,
["parameter1"] = 50,
["resource"] = "MEERASEW",
["savingthrow"] = savingthrow,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
		end
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter1"] = 49,
["resource"] = weaponRES,
["savingthrow"] = savingthrow,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter1"] = 50,
["resource"] = weaponRES,
["savingthrow"] = savingthrow,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
		IEex_Eval('EquipMostDamagingMelee()',targetID)
--]]
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter1"] = IEex_ReadDword(effectData + 0x18),
["parameter2"] = IEex_ReadDword(effectData + 0x1C),
["special"] = 49,
["resource"] = "MECRWEAP",
["savingthrow"] = savingthrow,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter1"] = IEex_ReadDword(effectData + 0x18),
["parameter2"] = IEex_ReadDword(effectData + 0x1C),
["special"] = 50,
["resource"] = "MECRWEAP",
["savingthrow"] = savingthrow,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
	else
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 111,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["resource"] = weaponRES,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["resource"] = "MEOFFANI",
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
--[[
		if timing == 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 112,
["target"] = 2,
["timing"] = 4,
["duration"] = duration,
["resource"] = weaponRES,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
		end
--]]
	end
end

function MECRWEAP(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - time_applied) / 15)
	end
	local weaponRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local slot = IEex_ReadDword(effectData + 0x44)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if bit.band(savingthrow, 0x100000) > 0 then
		local alreadyHasOldItem = false
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			local theoldItemSlot = IEex_ReadWord(eData + 0x62, 0x0)
			if theopcode == 288 and theparameter2 == 187 and theparent_resource == "MEOLDITM" and theoldItemSlot == slot then
				alreadyHasOldItem = true
			end
		end)
		if not alreadyHasOldItem then
			local oldSlotData = IEex_ReadDword(creatureData + 0x4AD8 + slot * 0x4)
			local oldItemRES = ""
			local oldItemCharges1 = 0
			local oldItemCharges2 = 0
			local oldItemCharges3 = 0
			local oldItemFlags = 0
			if oldSlotData > 0 then
				oldItemRES = IEex_ReadLString(oldSlotData + 0xC, 8)
				oldItemCharges1 = IEex_ReadSignedWord(oldSlotData + 0x18, 0x0)
				oldItemCharges2 = IEex_ReadSignedWord(oldSlotData + 0x1A, 0x0)
				oldItemCharges3 = IEex_ReadSignedWord(oldSlotData + 0x1C, 0x0)
				oldItemFlags = IEex_ReadDword(oldSlotData + 0x20)
			end
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["parameter1"] = oldItemCharges1 + oldItemCharges2 * 0x10000,
["parameter2"] = 187,
["parameter3"] = oldItemCharges3 + slot * 0x10000,
["savingthrow"] = savingthrow,
["special"] = oldItemFlags,
["resource"] = oldItemRES,
["parent_resource"] = "MEOLDITM",
["vvcresource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_id"] = targetID
})
		end
	end
	if timing == 0 then
--[[
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 112,
["target"] = 2,
["timing"] = 4,
["duration"] = duration,
["resource"] = weaponRES,
["savingthrow"] = savingthrow,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
--]]
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			if theopcode == 500 and theparameter1 == slot and theresource == "MEERASEW" then
				IEex_WriteDword(eData + 0x114, 1)
			end
		end)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 4,
["duration"] = duration,
["parameter1"] = slot,
["resource"] = "MEERASEW",
["savingthrow"] = savingthrow,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter1"] = slot,
["resource"] = weaponRES,
["savingthrow"] = savingthrow,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
	if bit.band(savingthrow, 0x10000) > 0 then
		local equippedSlot = IEex_ReadSignedWord(creatureData + 0x4BA4, 0x0)
		if slot == 10 and equippedSlot ~= 10 then
			IEex_Eval('SelectWeaponAbility(10,0)',targetID)
		elseif slot >= 11 and slot <= 14 then
			if equippedSlot < 11 or equippedSlot > 14 then
				IEex_Eval('EquipRanged()',targetID)
			end
			if slot ~= equippedSlot then
				IEex_WriteByte(creatureData + 0x3D3C, slot)
				IEex_Eval('SelectWeaponAbility(10,0)',targetID)
				IEex_Eval('SelectWeaponAbility(' .. slot .. ',0)',targetID)
				local newSlotData = IEex_ReadDword(creatureData + 0x4AD8 + slot * 0x4)
				local newItemRES = IEex_ReadLString(newSlotData + 0xC, 8)
				local newItemCharges1 = IEex_ReadWord(newSlotData + 0x18, 0x0)
				local newItemFlags = IEex_ReadDword(newSlotData + 0x20)
				local newItemName = -1
				local resWrapper = IEex_DemandRes(newItemRES, "ITM")
				if resWrapper:isValid() then
					local itemData = resWrapper:getData()
					newItemName = IEex_ReadDword(itemData + 0x8)
					if IEex_ReadDword(itemData + 0xC) > 0 and bit.band(newItemFlags, 0x1) > 0 then
						newItemName = IEex_ReadDword(itemData + 0xC)
					end
					for i = 0, 3, 1 do
						local weaponSlotOffset = creatureData + 0x342C + i * 0x78
						if IEex_ReadWord(weaponSlotOffset + 0x1C, 0x0) >= 11 and IEex_ReadWord(weaponSlotOffset + 0x1C, 0x0) <= 13 then
							IEex_WriteLString(weaponSlotOffset, IEex_ReadLString(itemData + 0x86, 8), 8)
							IEex_WriteDword(weaponSlotOffset + 0x8, newItemName)
							IEex_WriteWord(weaponSlotOffset + 0x1A, newItemCharges1)
							IEex_WriteWord(weaponSlotOffset + 0x1C, slot)
							IEex_WriteWord(weaponSlotOffset + 0x1E, 0)
							IEex_WriteWord(weaponSlotOffset + 0x28, IEex_ReadWord(itemData + 0x8E, 0x0))
							IEex_WriteDword(weaponSlotOffset + 0x2A, newItemName)
						end
					end
				end
			end
		elseif slot >= 43 and slot <= 50 then
			IEex_Eval('EquipMostDamagingMelee()',targetID)
		end
	end
end

function MEERASEW(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local slot = IEex_ReadDword(effectData + 0x18)
	local currentItemRES = IEex_GetItemSlotRES(targetID, slot)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local oldItemRES = ""
	local oldItemRES1 = ""
	local oldItemRES2 = ""
	local oldItemCharges1 = 0
	local oldItemCharges2 = 0
	local oldItemCharges3 = 0
	local oldItemFlags = 0
	if bit.band(savingthrow, 0x100000) > 0 then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			local theoldItemSlot = IEex_ReadWord(eData + 0x62, 0x0)
			if theopcode == 288 and theparameter2 == 187 and theparent_resource == "MEOLDITM" and theoldItemSlot == slot then
				oldItemRES = IEex_ReadLString(eData + 0x30, 8)
				oldItemRES1 = IEex_ReadDword(eData + 0x30)
				oldItemRES2 = IEex_ReadDword(eData + 0x34)
				oldItemCharges1 = IEex_ReadWord(eData + 0x1C, 0x0)
				oldItemCharges2 = IEex_ReadWord(eData + 0x1E, 0x0)
				oldItemCharges3 = IEex_ReadWord(eData + 0x60, 0x0)
				oldItemFlags = IEex_ReadDword(eData + 0x48)
				IEex_WriteDword(eData + 0x114, 1)
			end
		end)
	end
	if oldItemRES ~= "" then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 1,
["parameter1"] = oldItemRES1,
["parameter2"] = oldItemRES2,
["special"] = slot,
["resource"] = "MECRWEAP",
["savingthrow"] = 0x10000,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
		local oldSlotData = IEex_ReadDword(creatureData + 0x4AD8 + slot * 0x4)
		if oldSlotData > 0 then
			IEex_WriteWord(oldSlotData + 0x18, oldItemCharges1)
			IEex_WriteWord(oldSlotData + 0x1A, oldItemCharges2)
			IEex_WriteWord(oldSlotData + 0x1C, oldItemCharges3)
			IEex_WriteDword(oldSlotData + 0x20, oldItemFlags)
		end
	else
		if currentItemRES ~= "" then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 112,
["target"] = 2,
["timing"] = 1,
["resource"] = currentItemRES,
["savingthrow"] = savingthrow,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID,
})
		end
		if slot >= 11 and slot <= 13 then
			local newSlot = 10
			for i = 11, 13, 1 do
				if i ~= slot and newSlot == 10 and IEex_ReadDword(creatureData + 0x4AD8 + i * 0x4) > 0 then
					newSlot = i
				end
			end
			local newSlotData = IEex_ReadDword(creatureData + 0x4AD8 + newSlot * 0x4)
			local newItemRES = IEex_ReadLString(newSlotData + 0xC, 8)
			local newItemCharges1 = IEex_ReadWord(newSlotData + 0x18, 0x0)
			local newItemFlags = IEex_ReadDword(newSlotData + 0x20)
			local newItemName = -1
			local resWrapper = IEex_DemandRes(newItemRES, "ITM")
			if resWrapper:isValid() then
				local itemData = resWrapper:getData()
				newItemName = IEex_ReadDword(itemData + 0x8)
				if IEex_ReadDword(itemData + 0xC) > 0 and bit.band(newItemFlags, 0x1) > 0 then
					newItemName = IEex_ReadDword(itemData + 0xC)
				end
				for i = 0, 3, 1 do
					local weaponSlotOffset = creatureData + 0x342C + i * 0x78
					if IEex_ReadWord(weaponSlotOffset + 0x1C, 0x0) == slot then
						IEex_WriteLString(weaponSlotOffset, IEex_ReadLString(itemData + 0x86, 8), 8)
						IEex_WriteDword(weaponSlotOffset + 0x8, newItemName)
						if newSlot == 10 then
							IEex_WriteLString(weaponSlotOffset + 0xC, "", 8)
							IEex_WriteDword(weaponSlotOffset + 0x14, -1)
						end
						IEex_WriteWord(weaponSlotOffset + 0x1A, newItemCharges1)
						IEex_WriteWord(weaponSlotOffset + 0x1C, newSlot)
						IEex_WriteWord(weaponSlotOffset + 0x1E, 0)
						IEex_WriteWord(weaponSlotOffset + 0x28, IEex_ReadWord(itemData + 0x8E, 0x0))
						IEex_WriteDword(weaponSlotOffset + 0x2A, newItemName)
					end
				end
				if newSlot > 10 then
					IEex_WriteByte(creatureData + 0x3D3C, newSlot)
					if IEex_ReadByte(creatureData + 0x4BA4, 0x0) == 10 then
						IEex_Eval('SelectWeaponAbility(' .. newSlot .. ',0)',targetID)
					end
				else
					IEex_WriteByte(creatureData + 0x3D3C, 0)
					IEex_Eval('SelectWeaponAbility(10,0)',targetID)
				end
			end
			resWrapper:free()
		elseif slot >= 43 then
			local weaponSlotIndex = slot - 43
			local weaponSlotOffset = creatureData + 0x342C + weaponSlotIndex * 0x3C
			if slot % 2 == 1 then
				local fistWeaponRES = IEex_GetItemSlotRES(targetID, 10)
				local resWrapper = IEex_DemandRes(fistWeaponRES, "ITM")
				if resWrapper:isValid() then
					local itemData = resWrapper:getData()
					IEex_WriteLString(weaponSlotOffset, IEex_ReadLString(itemData + 0x86, 8), 8)
					IEex_WriteDword(weaponSlotOffset + 0x8, IEex_ReadDword(itemData + 0x8))
					IEex_WriteDword(weaponSlotOffset + 0x2A, IEex_ReadDword(itemData + 0x8))
				end
				resWrapper:free()
				IEex_WriteLString(weaponSlotOffset + 0xC, "", 8)
				IEex_WriteDword(weaponSlotOffset + 0x14, -1)
				IEex_WriteWord(weaponSlotOffset + 0x1A, 0)
				IEex_WriteWord(weaponSlotOffset + 0x1C, 10)
				IEex_WriteWord(weaponSlotOffset + 0x1E, 0)
			else
				IEex_WriteLString(weaponSlotOffset, "", 8)
				IEex_WriteDword(weaponSlotOffset + 0x8, -1)
				IEex_WriteLString(weaponSlotOffset + 0xC, "", 8)
				IEex_WriteDword(weaponSlotOffset + 0x14, -1)
				IEex_WriteWord(weaponSlotOffset + 0x1A, -1)
				IEex_WriteWord(weaponSlotOffset + 0x1C, -1)
				IEex_WriteWord(weaponSlotOffset + 0x1E, -1)
				IEex_WriteDword(weaponSlotOffset + 0x2A, -1)
			end
		end
	end
end

function MEQUIPLE(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local duration = IEex_ReadDword(effectData + 0x44)
	if IEex_ReadLString(effectData + 0x92, 2) == "PR" then
		duration = math.floor(duration * IEex_GetActorStat(sourceID, 54) / 100)
	end
	local quiverData = IEex_ReadDword(creatureData + 0x4B04)
	local quiverRES = ""
	local quiverNum = 0
	local quiverFlags = 0
	if quiverData > 0 then
		quiverRES = IEex_ReadLString(quiverData + 0xC, 8)
		quiverNum = IEex_ReadWord(quiverData + 0x18, 0x0)
		quiverFlags = IEex_ReadByte(quiverData + 0x20, 0x0)
	end
--[[
	local hasBow = false
	if IEex_GetActorSpellState(targetID, 241) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 241 then
				if theparameter1 == 15 then
					hasBow = true
				end
			end
		end)
	end
--]]
	if quiverRES ~= "" then
		if IEex_ReadLString(quiverData + 0xC, 6) ~= "USQUIP" then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 4,
["duration"] = duration,
["parameter1"] = 11,
["resource"] = quiverRES,
["savingthrow"] = 0x100000,
["parent_resource"] = "MEQUIPLE",
["source_id"] = targetID
})
		end
	end
	if not IEex_GetActorSpellState(targetID, 187) then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 1,
["parameter1"] = quiverNum,
["parameter2"] = 187,
["special"] = quiverFlags,
["resource"] = quiverRES,
["parent_resource"] = "MEQUIPLE",
["source_id"] = targetID
})
	else
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theopcode == 143 and theparameter1 == 11 and theparent_resource == "MEQUIPLE" then
				IEex_WriteDword(eData + 0x28, IEex_ReadDword(effectData + 0x24) + duration * 15)
			end
		end)
	end
end

function MEQUIPL2(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local quiverData = IEex_ReadDword(creatureData + 0x4B04)
	if quiverData > 0 and IEex_ReadByte(creatureData + 0x34C0, 0x0) == 11 and IEex_ReadByte(creatureData + 0x3D3C, 0x0) == 11 then
		IEex_WriteByte(creatureData + 0x4BA4, 11)
		local resWrapper = IEex_DemandRes(IEex_ReadLString(quiverData + 0xC, 8), "ITM")
		if resWrapper:isValid() then
			local itemData = resWrapper:getData()
			IEex_WriteWord(creatureData + 0x34BC, IEex_ReadWord(quiverData + 0x18, 0x0))
			IEex_WriteLString(creatureData + 0x34A4, IEex_ReadLString(itemData + 0x3A, 8), 8)
			local thename1 = IEex_ReadDword(itemData + 0x8)
			local thename2 = IEex_ReadDword(itemData + 0xC)
			if thename2 > 0 and thename2 < 999999 and (IEex_ReadWord(itemData + 0x42, 0x0) == 0 or bit.band(IEex_ReadByte(quiverData + 0x20, 0x0), 0x1) > 0) then
				IEex_WriteDword(creatureData + 0x34AC, thename2)
			else
				IEex_WriteDword(creatureData + 0x34AC, thename1)
			end
		end
		resWrapper:free()
	end
end

function MEQUIVNO(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local quiverData = IEex_ReadDword(creatureData + 0x4B04)
	local quiverRES = ""
	if quiverData > 0 then
		quiverRES = IEex_ReadLString(quiverData + 0xC, 8)
	end
--	if IEex_GetActorSpellState(targetID, 187) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if theopcode == 288 and theparameter2 == 187 and theresource == quiverRES and quiverRES ~= "" then
				IEex_WriteWord(quiverData + 0x18, theparameter1)
				IEex_WriteByte(quiverData + 0x20, thespecial)
			end
		end)
--	end
	if IEex_ReadByte(creatureData + 0x34C0, 0x0) == 11 and IEex_ReadByte(creatureData + 0x3D3C, 0x0) == 11 and IEex_ReadByte(creatureData + 0x4BA4, 0x0) == 10 then
		if IEex_ReadDword(creatureData + 0x4B04) > 0 then
			IEex_WriteByte(creatureData + 0x4BA4, 11)
		elseif IEex_ReadDword(creatureData + 0x4B08) > 0 then
			IEex_WriteByte(creatureData + 0x34C0, 12)
			IEex_WriteByte(creatureData + 0x3D3C, 12)
			IEex_WriteByte(creatureData + 0x4BA4, 12)
		elseif IEex_ReadDword(creatureData + 0x4B0C) > 0 then
			IEex_WriteByte(creatureData + 0x34C0, 13)
			IEex_WriteByte(creatureData + 0x3D3C, 13)
			IEex_WriteByte(creatureData + 0x4BA4, 13)
		else
			IEex_WriteByte(creatureData + 0x34C0, 10)
			IEex_WriteByte(creatureData + 0x3D3C, 0)
		end
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "MEQUIPLE",
["parent_resource"] = "MEQUIPLE",
["source_id"] = targetID
})

end

IEex_AddScreenEffectsGlobal("MEREPLIT", function(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local opcode = IEex_ReadDword(effectData + 0xC)
	if opcode == 143 then
		local parameter1 = IEex_ReadDword(effectData + 0x18)
		local savingthrow = IEex_ReadDword(effectData + 0x3C)
		if (parameter1 >= 10 and parameter1 <= 17) or (parameter1 >= 43 and parameter1 <= 50) then
			local itemRES = IEex_ReadLString(effectData + 0x2C, 8)
			local currentWeaponSet = IEex_ReadByte(creatureData + 0x4C68, 0x0)
			local resWrapper = IEex_DemandRes(itemRES, "ITM")
			local itemName = 0
			local itemIcon = ""
			local abilityTarget = 0
			if resWrapper:isValid() then
				local itemData = resWrapper:getData()
				local requiredLore = IEex_ReadWord(itemData + 0x42, 0x0)
				if requiredLore == 0 then
					itemName = IEex_ReadDword(itemData + 0xC)
				else
					itemName = IEex_ReadDword(itemData + 0x8)
				end
				itemIcon = IEex_ReadLString(itemData + 0x3A, 8)
				if IEex_ReadWord(itemData + 0x68, 0x0) > 0 then
					abilityTarget = IEex_ReadWord(itemData + 0x8E, 0x0)
				end
			end
			resWrapper:free()
			if parameter1 >= 15 and parameter1 <= 17 then
				local quickItemOffset = creatureData + 0x3828 + (parameter1 - 15) * 0x3C
				IEex_WriteWord(quickItemOffset + 0x1A, 2)
				IEex_WriteDword(quickItemOffset + 0x1C, parameter1)
				IEex_WriteLString(quickItemOffset, itemIcon, 8)
				IEex_WriteDword(quickItemOffset + 0x8, itemName)
				IEex_WriteWord(quickItemOffset + 0x28, abilityTarget)
				IEex_WriteDword(quickItemOffset + 0x2A, itemName)
				if IEex_GetItemSlotRES(targetID, parameter1) == itemRES then
					IEex_WriteWord(quickItemOffset + 0x18, IEex_ReadSignedWord(quickItemOffset + 0x18, 0x0) + 1)
					local itemSlotData = IEex_ReadDword(creatureData + 0x4AD8 + parameter1 * 0x4)
					local charges1 = IEex_ReadSignedWord(itemSlotData + 0x18, 0x0)
					if charges1 == 0 then
						charges1 = 1
					end
					IEex_WriteWord(quickItemOffset + 0x18, charges1 + 1)
					IEex_WriteWord(itemSlotData + 0x18, charges1 + 1)
					return true
				else
					IEex_WriteWord(quickItemOffset + 0x18, 1)
				end
			else
				for i = 0, 7, 1 do
					local weaponSetOffset = creatureData + 0x342C + i * 0x3C
					if IEex_ReadByte(weaponSetOffset + 0x1C, 0x0) == parameter1 or 43 + i == parameter1 then
						IEex_WriteDword(weaponSetOffset + 0x1C, parameter1)
						IEex_WriteLString(weaponSetOffset, itemIcon, 8)
						IEex_WriteDword(weaponSetOffset + 0x8, itemName)
						IEex_WriteDword(weaponSetOffset + 0x2A, itemName)
					end
				end
			end
		end
	end
end)

ex_real_projectile = {
[68] = 67,
[69] = 67,
[70] = 67,
[71] = 67,
[72] = 67,
[73] = 67,
[74] = 67,
[75] = 67,
[76] = 67,
[77] = 67,
}
function MESPELLT(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if targetID == sourceID or not IEex_IsSprite(sourceID, false) or not IEex_IsSprite(targetID, false) then return end
	local sourceData = IEex_GetActorShare(sourceID)
	if IEex_GetActorSpellState(targetID, 193) then
		local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
		local special = IEex_ReadDword(effectData + 0x44)
		local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
		local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
		local sourceSpell = IEex_ReadLString(effectData + 0x18, 8)
		if sourceSpell == "" then
			sourceSpell = parent_resource
		end
		local classSpellLevel = IEex_GetClassSpellLevel(sourceID, casterClass, sourceSpell)
		if classSpellLevel == 0 then
			classSpellLevel = IEex_ReadDword(effectData + 0x14)
		end
		local spellBlocked = false
		local spellTurned = false
		local endTurningRES = "DEFA"
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 193 and spellBlocked == false and spellTurned == false then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				local thespecial = IEex_ReadDword(eData + 0x48)
				if (theparameter1 > 0 or bit.band(thesavingthrow, 0x10000) > 0) and ((thespecial >= classSpellLevel and classSpellLevel > 0) or (theresource == sourceSpell and theresource ~= "")) and (bit.band(savingthrow, 0x40000) == 0 or bit.band(thesavingthrow, 0x40000) > 0) then
					if bit.band(thesavingthrow, 0x80000) == 0 then
						spellBlocked = true
					end
					if bit.band(thesavingthrow, 0x100000) == 0 then
						spellTurned = true
					end
					if bit.band(thesavingthrow, 0x10000) == 0 then
						theparameter1 = theparameter1 - classSpellLevel
						if theparameter1 <= 0 and bit.band(thesavingthrow, 0x20000) == 0 then
							endTurningRES = IEex_ReadLString(eData + 0x94, 8)
						else
							IEex_WriteDword(eData + 0x1C, theparameter1)
						end
					end
				end
			end
		end)
		if endTurningRES ~= "DEFA" then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = endTurningRES,
["source_id"] = targetID
})
		end
		if spellTurned then
			local projectile = IEex_ReadDword(effectData + 0x9C)
			if ex_real_projectile[projectile] ~= nil then
				projectile = ex_real_projectile[projectile]
			end
			if bit.band(savingthrow, 0x10000) > 0 then
				projectile = special
			end
			local casterlvl = IEex_ReadDword(effectData + 0xC4)
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 430,
["target"] = 2,
["timing"] = 0,
["parameter2"] = projectile,
["resource"] = sourceSpell,
["parent_resource"] = sourceSpell,
["casterlvl"] = casterlvl,
["source_x"] = IEex_ReadDword(creatureData + 0x6),
["source_y"] = IEex_ReadDword(creatureData + 0xA),
["target_x"] = IEex_ReadDword(sourceData + 0x6),
["target_y"] = IEex_ReadDword(sourceData + 0xA),
["source_id"] = targetID
})
		end
		if spellBlocked then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["resource"] = sourceSpell,
["parent_resource"] = sourceSpell,
["source_id"] = sourceID
})
		end
	end
end

function METOUGHN(effectData, creatureData)
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local totalLevel = IEex_ReadByte(creatureData + 0x626, 0x0)
	local barbarianLevel = IEex_ReadByte(creatureData + 0x627, 0x0)
	local totalLevelNoted = IEex_ReadDword(effectData + 0x5C)
	local barbarianLevelNoted = IEex_ReadDword(effectData + 0x60)
	local extraHP = 0
--	IEex_DS(totalLevel .. " vs. " .. totalLevelNoted)
--		IEex_DS(IEex_ReadWord(creatureData + 0x5C0, 0x0) .. "/" .. IEex_ReadWord(creatureData + 0x5C2, 0x0))
--		IEex_DS(IEex_GetActorStat(targetID, 1))
	if totalLevel > totalLevelNoted and (totalLevelNoted == 0 or IEex_ReadSignedWord(creatureData + 0x5C2, 0x0) <= IEex_GetActorStat(targetID, 1)) then
		extraHP = totalLevel - totalLevelNoted
		IEex_WriteDword(effectData + 0x5C, totalLevel)
		if barbarianLevel > barbarianLevelNoted then
			extraHP = extraHP + (barbarianLevel - barbarianLevelNoted) * 2
			IEex_WriteDword(effectData + 0x60, barbarianLevel)
		end
	end
	if extraHP > 0 then
--		IEex_DS(extraHP)
--		IEex_DS(IEex_ReadWord(creatureData + 0x5C0, 0x0) .. "/" .. IEex_ReadWord(creatureData + 0x5C2, 0x0))
--		IEex_DS(IEex_GetActorStat(targetID, 1))
--		IEex_WriteWord(creatureData + 0x5C0, IEex_ReadSignedWord(creatureData + 0x5C0, 0x0) + extraHP)
--		IEex_WriteWord(creatureData + 0x5C2, IEex_ReadSignedWord(creatureData + 0x5C2, 0x0) + extraHP)

		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 18,
["target"] = 2,
["timing"] = 1,
["parameter1"] = extraHP,
["source_id"] = targetID
})

	end
end

function MEKEEPHP(effectData, creatureData)
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local currentHP = IEex_ReadSignedWord(creatureData + 0x5C0, 0x0)
	local maxHP = IEex_ReadSignedWord(creatureData + 0x5C2, 0x0)
	local storedHP = IEex_ReadSignedWord(creatureData + 0x708, 0x0)
	if currentHP == maxHP and storedHP > currentHP then
		IEex_WriteWord(creatureData + 0x5C0, storedHP)
	end
end

function MECOUNTE(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	IEex_SetToken("EXCSNAM1", IEex_GetActorName(targetID))
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local actionID = IEex_ReadWord(creatureData + 0x476, 0x0)
	if actionID == 31 or actionID == 95 or actionID == 113 or actionID == 114 or actionID == 191 or actionID == 192 then
		local casterClass = IEex_ReadSignedByte(creatureData + 0x530, 0x0)
		local classSpellLevel = IEex_ReadSignedByte(creatureData + 0x534, 0x0)
		local spellRES = IEex_GetActorSpellRES(targetID)
		if ex_true_spell[spellRES] ~= nil then
			spellRES = ex_true_spell[spellRES]
		end
		if classSpellLevel <= 0 and (ex_listspll[spellRES] ~= nil or ex_listdomn[spellRES] ~= nil) then
			if casterClass <= 0 then
				if IEex_GetActorStat(targetID, 97) > 0 and ex_listspll[spellRES][1] > 0 then
					casterClass = 2
				elseif IEex_GetActorStat(targetID, 98) > 0 and ex_listspll[spellRES][2] > 0 then
					casterClass = 3
				elseif IEex_GetActorStat(targetID, 99) > 0 and ex_listspll[spellRES][3] > 0 then
					casterClass = 4
				elseif IEex_GetActorStat(targetID, 102) > 0 and ex_listspll[spellRES][4] > 0 then
					casterClass = 7
				elseif IEex_GetActorStat(targetID, 103) > 0 and ex_listspll[spellRES][5] > 0 then
					casterClass = 8
				elseif IEex_GetActorStat(targetID, 105) > 0 and ex_listspll[spellRES][6] > 0 then
					casterClass = 10
				elseif IEex_GetActorStat(targetID, 105) > 0 and ex_listspll[spellRES][6] > 0 then
					casterClass = 11
				end
			end
			classSpellLevel = IEex_GetClassSpellLevel(targetID, casterClass, spellRES)
		end
		if classSpellLevel <= 0 then
			local resWrapper = IEex_DemandRes(spellRES, "SPL")
			if resWrapper:isValid() then
				local spellData = resWrapper:getData()
				if IEex_ReadWord(spellData + 0x1C, 0x0) == 1 or IEex_ReadWord(spellData + 0x1C, 0x0) == 2 then
					classSpellLevel = IEex_ReadDword(spellData + 0x34)
				end
			end
			resWrapper:free()
		end
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["parameter1"] = ex_tra_55483,
["source_id"] = sourceID
})
		local spells = IEex_FetchSpellInfo(sourceID, {1, 2, 3, 4, 5, 6, 7, 8})
		local sourceHasSpell = false
		if classSpellLevel > 0 then
			for i = 1, 9, 1 do
				for cType, levelList in pairs(spells) do
					if #levelList >= i then
						local levelI = levelList[i]
						local maxCastable = levelI[1]
						local sorcererCastableCount = levelI[2]
						local levelISpells = levelI[3]
						if #levelISpells > 0 then
							for i2, spell in ipairs(levelISpells) do
								if spellRES == spell["resref"] then
									if cType == 1 or cType == 6 then
										if sorcererCastableCount > 0 then
											sourceHasSpell = true
										end
									else
										if spell["castableCount"] > 0 then
											sourceHasSpell = true
										end
									end
								end
							end
						end
					end
				end
			end
		end
		if sourceHasSpell then
			IEex_WriteWord(creatureData + 0x476, 0)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 138,
["target"] = 2,
["timing"] = 0,
["parameter2"] = 4,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 0,
["parameter2"] = 67,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 0,
["resource"] = "CASTB",
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = -1,
["parameter2"] = 9,
["special"] = 1,
["savingthrow"] = 0x2FF0000,
["resource"] = "EXMODMEM",
["vvcresource"] = spellRES,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["parameter1"] = ex_tra_55481,
["source_id"] = sourceID
})
		else
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["parameter1"] = ex_tra_55482,
["source_id"] = sourceID
})
		end
	else
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["parameter1"] = ex_tra_55484,
["source_id"] = sourceID
})
	end
end

function MEKENSEI(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local casterlvl = IEex_GetActorStat(targetID, 100)
	if casterlvl < 3 then
		casterlvl = 3
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USKENBON",
["source_id"] = targetID
})

	if IEex_GetActorSpellState(targetID, 241) then
		local hasArmor = false
		local hasMeleeWeapon = false
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 241 then
				local thespecialtype = IEex_ReadByte(eData + 0x48, 0x0)
				if thespecialtype == 1 or thespecialtype == 3 then
					hasArmor = true
				elseif thespecialtype == 5 then
					hasMeleeWeapon = true
				end
			end
		end)
		if hasArmor == false and hasMeleeWeapon == true then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 54,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = math.floor(casterlvl / 3),
["parent_resource"] = "USKENBON",
["source_id"] = targetID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 73,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = math.floor(casterlvl / 3),
["parent_resource"] = "USKENBON",
["source_id"] = targetID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = 2,
["parent_resource"] = "USKENBON",
["source_id"] = targetID
})
		end
	end
end

function MEKENSE2(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local fighterLevel = IEex_GetActorStat(targetID, 100)
	if fighterLevel < 3 then
		fighterLevel = 3
	end
--	if IEex_GetActorSpellState(targetID, 241) then
		local hasArmor = false
		local hasMeleeWeapon = false
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 241 then
				local thespecialtype = IEex_ReadByte(eData + 0x48, 0x0)
				if (thespecialtype == 1 and (theparameter1 ~= 67 or not ex_elven_chainmail_counts_as_unarmored)) or thespecialtype == 3 then
					hasArmor = true
				elseif thespecialtype == 5 then
					hasMeleeWeapon = true
				end
			end
		end)
		if hasArmor == false and hasMeleeWeapon == true then
			IEex_WriteWord(creatureData + 0x92C, IEex_ReadSignedWord(creatureData + 0x92C, 0x0) + 2)
			IEex_WriteWord(creatureData + 0x938, IEex_ReadSignedWord(creatureData + 0x938, 0x0) + math.floor(fighterLevel / 3))
			IEex_WriteWord(creatureData + 0x9A6, IEex_ReadSignedWord(creatureData + 0x9A6, 0x0) + math.floor(fighterLevel / 3))
		end
--	end
end

ex_armor_penalties = {
[41] = {5, 99, 1},
[47] = {50, 99, 10},
[49] = {15, 99, 2},
[53] = {5, 99, 1},
[60] = {10, 6, 0},
[61] = {15, 5, 1},
[62] = {30, 2, 5},
[63] = {40, 0, 7},
[64] = {40, 0, 7},
[65] = {35, 1, 6},
[66] = {20, 4, 3},
[67] = {0, 99, 0},
[68] = {30, 2, 5},
}
function MEARMMAS(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USARMMAS",
["source_id"] = targetID
})
	local armorType = 67
	if IEex_GetActorSpellState(targetID, 241) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 241 then
				if theparameter1 >= 60 and theparameter1 <= 68 then
					armorType = theparameter1
				end
			end
		end)
		local dexterityBonus = math.floor((IEex_GetActorStat(targetID, 40) - 10) / 2)
		local dexterityAdjust = 0
		local maxDexBonus = 99
		local armorCheckPenalty = 0
		if ex_armor_penalties[armorType] ~= nil then
			maxDexBonus = ex_armor_penalties[armorType][2]
			armorCheckPenalty = ex_armor_penalties[armorType][3]
			if dexterityBonus > maxDexBonus then
				dexterityAdjust = dexterityBonus - maxDexBonus
			end
		end
		if armorType == 60 or armorType == 61 then
			if armorCheckPenalty > 0 then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 59,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = armorCheckPenalty + dexterityAdjust,
["parent_resource"] = "USARMMAS",
["source_id"] = targetID
})
--[[
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 90,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = armorCheckPenalty + dexterityAdjust,
["parent_resource"] = "USARMMAS",
["source_id"] = targetID
})
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 91,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = armorCheckPenalty + dexterityAdjust,
["parent_resource"] = "USARMMAS",
["source_id"] = targetID
})
--]]
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 92,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = armorCheckPenalty + dexterityAdjust,
["parent_resource"] = "USARMMAS",
["source_id"] = targetID
})
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 297,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = armorCheckPenalty + dexterityAdjust,
["parent_resource"] = "USARMMAS",
["source_id"] = targetID
})
			end
			if dexterityAdjust > 0 then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = dexterityAdjust,
["parent_resource"] = "USARMMAS",
["source_id"] = targetID
})
			end
		end
	end
end

function MEARMMA2(effectData, creatureData)
	if true then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local armorType = 67
	if IEex_GetActorSpellState(targetID, 241) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 241 then
				if theparameter1 >= 60 and theparameter1 <= 68 then
					armorType = theparameter1
				end
			end
		end)
		local dexterityBonus = math.floor((IEex_GetActorStat(targetID, 40) - 10) / 2)
		local dexterityAdjust = 0
		local maxDexBonus = 99
		local armorCheckPenalty = 0
		if ex_armor_penalties[armorType] ~= nil then
			maxDexBonus = ex_armor_penalties[armorType][2]
			armorCheckPenalty = ex_armor_penalties[armorType][3]
			if dexterityBonus > maxDexBonus then
				dexterityAdjust = dexterityBonus - maxDexBonus
			end
		end
		if armorType == 60 or armorType == 61 then
			if armorCheckPenalty > 0 then
				IEex_WriteByte(creatureData + 0xA6A, IEex_ReadSignedByte(creatureData + 0xA6A, 0x0) + armorCheckPenalty + dexterityAdjust)
				IEex_WriteByte(creatureData + 0xA6D, IEex_ReadSignedByte(creatureData + 0xA6D, 0x0) + armorCheckPenalty + dexterityAdjust)
				IEex_WriteByte(creatureData + 0xA6F, IEex_ReadSignedByte(creatureData + 0xA6F, 0x0) + armorCheckPenalty + dexterityAdjust)
			end
			if dexterityAdjust > 0 then
				IEex_WriteWord(creatureData + 0x92C, IEex_ReadSignedWord(creatureData + 0x92C, 0x0) + dexterityAdjust)
			end
		end
	end
end

function MEARMARC(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USARMARC",
["source_id"] = targetID
})
	local armorType = 0
	local shieldType = 0
	if IEex_GetActorSpellState(targetID, 241) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 241 then
				local thespecialtype = IEex_ReadByte(eData + 0x48, 0x0)
				if theparameter1 >= 60 and theparameter1 <= 68 then
					armorType = theparameter1
				elseif thespecialtype == 3 then
					shieldType = theparameter1
				end
			end
		end)
		local armoredArcanaFeatCount = IEex_ReadByte(creatureData + 0x781, 0x0)
		local spellFailure = 0
		if ex_armor_penalties[armorType] ~= nil then
			if (armoredArcanaFeatCount >= 1 and (armorType == 60 or armorType == 61)) or (armoredArcanaFeatCount >= 2 and (armorType == 62 or armorType == 66 or armorType == 68)) or (armoredArcanaFeatCount >= 3 and (armorType == 63 or armorType == 64 or armorType == 65)) then
				spellFailure = spellFailure + ex_armor_penalties[armorType][1]
			end
		end
		if ex_armor_penalties[shieldType] ~= nil then
			if (armoredArcanaFeatCount >= 1 and (shieldType == 41 or shieldType == 53)) or (armoredArcanaFeatCount >= 2 and shieldType == 49) or (armoredArcanaFeatCount >= 3 and shieldType == 47) then
				spellFailure = spellFailure + ex_armor_penalties[shieldType][1]
			end
		end
		if spellFailure > 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 60,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = 0 - spellFailure,
["parent_resource"] = "USARMARC",
["source_id"] = targetID
})
		end
	end
end

function MERAPREL(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USRAPREX",
["source_id"] = targetID
})
	local oneAPRRES = ""
	local crossbowRES = ""
	if IEex_GetActorSpellState(targetID, 241) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thetiming = IEex_ReadDword(eData + 0x24)
			if thetiming == 2 then
				if theopcode == 1 and theparameter1 == 1 and theparameter2 == 1 then
					oneAPRRES = IEex_ReadLString(eData + 0x94, 8)
				elseif theopcode == 288 and theparameter1 == 27 and theparameter2 == 241 then
					crossbowRES = IEex_ReadLString(eData + 0x94, 8)
				end
			end
		end)
	end
	if oneAPRRES ~= "" and crossbowRES ~= "" and oneAPRRES == crossbowRES then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 1,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = 1,
["parent_resource"] = "USRAPREX",
["source_id"] = targetID
})
	end
--[[
	local rapidReloadFeatID = ex_feat_name_id["ME_RAPID_RELOAD"]
	if rapidReloadFeatID ~= nil then
		local hasRapidReloadFeat = IEex_ReadByte(creatureData + 0x744 + rapidReloadFeatID, 0x0)
		if hasRapidReloadFeat then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USRAPREX",
["source_id"] = targetID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 1,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = 1,
["parent_resource"] = "USRAPREX",
["source_id"] = targetID
})
		end
	end
--]]
end

function MEIMPTWF(effectData, creatureData)
	if true then return end
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local sourceData = IEex_GetActorShare(sourceID)
--[[
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USIMPTWX",
["source_id"] = targetID
})
--]]
	local weaponCount = 0
	local wearingLightArmor = true
	if math.random(100) <= 20 then
		if IEex_GetActorSpellState(sourceID, 241) then
			IEex_IterateActorEffects(sourceID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
				if theopcode == 288 and theparameter2 == 241 then
					if thespecial == 5 or thespecial == 6 then
						weaponCount = weaponCount + 1
					elseif (theparameter1 >= 62 and theparameter1 <= 66) or theparameter1 == 68 then
						wearingLightArmor = false
					end
				end
			end)
		end
		if weaponCount >= 2 and (IEex_GetActorStat(sourceID, 103) < 9 or wearingLightArmor or (IEex_ReadByte(sourceData + 0x5EC, 0x0) >= 16 and bit.band(IEex_ReadDword(sourceData + 0x75C), 0x2) > 0 and bit.band(IEex_ReadDword(sourceData + 0x764), 0x40) > 0)) then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 442,
["target"] = 2,
["timing"] = 0,
["parent_resource"] = "USIMPTWX",
["source_id"] = sourceID
})
		end
	end
end
--[[
function MEIMPTW2(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local weaponCount = 0
	local wearingLightArmor = true
	if math.random(100) <= 20 then
		if IEex_GetActorSpellState(sourceID, 241) then
			IEex_IterateActorEffects(sourceID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
				if theopcode == 288 and theparameter2 == 241 then
					if thespecial == 5 or thespecial == 6 then
						weaponCount = weaponCount + 1
					elseif (theparameter1 >= 62 and theparameter1 <= 66) or theparameter1 == 68 then
						wearingLightArmor = false
					end
				end
			end)
		end
		if weaponCount >= 2 and (IEex_GetActorStat(sourceID, 103) < 9 or wearingLightArmor or (IEex_ReadByte(sourceData + 0x5EC, 0x0) >= 16 and bit.band(IEex_ReadDword(sourceData + 0x75C), 0x2) > 0 and bit.band(IEex_ReadDword(sourceData + 0x764), 0x40) > 0)) then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 442,
["target"] = 2,
["timing"] = 0,
["parent_resource"] = "USIMPTWX",
["source_id"] = sourceID
})
		end
	end
end
--]]
function MESHLDFO(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USSHLDFD",
["source_id"] = targetID
})
	local hasShield = false
	if IEex_GetActorSpellState(targetID, 241) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
			if theopcode == 288 and theparameter2 == 241 then
				if thespecial == 3 then
					hasShield = true
				end
			end
		end)
	end
	if hasShield then
		local shieldFocusFeatID = ex_feat_name_id["ME_SHIELD_FOCUS"]
		if shieldFocusFeatID ~= nil then
			local shieldFocusBonus = IEex_ReadByte(creatureData + 0x744 + shieldFocusFeatID, 0x0) * parameter1
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = shieldFocusBonus,
["parent_resource"] = "USSHLDFD",
["source_id"] = targetID
})
		end
	end
end

function MESHLDF2(effectData, creatureData)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local shieldRES = ""
	local shieldBonus = 0
	if IEex_GetActorSpellState(targetID, 241) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
			if theopcode == 288 and theparameter2 == 241 then
				if thespecial == 3 then
					shieldRES = IEex_ReadLString(eData + 0x94, 8)
				end
			end
		end)
	end
	if shieldRES ~= "" then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theopcode == 0 and theparameter2 == 3 and theparent_resource == shieldRES then
				shieldBonus = theparameter1
			end
		end)
		shieldBonus = shieldBonus + IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_SHIELD_FOCUS"], 0x0) * parameter1
		if shieldBonus > IEex_ReadSignedWord(creatureData + 0x92A, 0x0) then
			IEex_WriteWord(creatureData + 0x92A, shieldBonus)
		end
	end
end

function METWDEFE(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USTWDEFD",
["source_id"] = targetID
})
	local weaponCount = 0
	local wearingLightArmor = true
	if IEex_GetActorSpellState(targetID, 241) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
			if theopcode == 288 and theparameter2 == 241 then
				if thespecial == 5 or thespecial == 6 then
					weaponCount = weaponCount + 1
				elseif (theparameter1 >= 62 and theparameter1 <= 66) or theparameter1 == 68 then
					wearingLightArmor = false
				end
			end
		end)
	end
	if weaponCount >= 2 and (IEex_GetActorStat(targetID, 103) == 0 or wearingLightArmor or bit.band(IEex_ReadDword(creatureData + 0x764), 0x40) > 0) then
		local twoWeaponDefenseFeatID = ex_feat_name_id["ME_TWO_WEAPON_DEFENSE"]
		if twoWeaponDefenseFeatID ~= nil then
			local twoWeaponDefenseBonus = IEex_ReadByte(creatureData + 0x744 + twoWeaponDefenseFeatID, 0x0) * parameter1
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter1"] = twoWeaponDefenseBonus,
["parent_resource"] = "USTWDEFD",
["source_id"] = targetID
})
		end
	end
end

function METWDEF2(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local weaponCount = 0
	local wearingLightArmor = true
--	if IEex_GetActorSpellState(targetID, 241) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
			if theopcode == 288 and theparameter2 == 241 then
				if thespecial == 5 or thespecial == 6 then
					weaponCount = weaponCount + 1
				elseif (theparameter1 >= 62 and theparameter1 <= 66) or theparameter1 == 68 then
					wearingLightArmor = false
				end
			end
		end)
--	end
	if weaponCount >= 2 and (IEex_GetActorStat(targetID, 103) == 0 or wearingLightArmor or bit.band(IEex_ReadDword(creatureData + 0x764), 0x40) > 0) then
		local twoWeaponDefenseBonus = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_TWO_WEAPON_DEFENSE"], 0x0) * parameter1
		IEex_WriteWord(creatureData + 0x92A, IEex_ReadSignedWord(creatureData + 0x92A, 0x0) + twoWeaponDefenseBonus)
	end
end

extra_hands = {[32558] = 4, [60365] = 6, [60697] = 4,}
ex_whirla_index = 1
ex_difficulty_attack_bonus = {-4, -2, 0, 3, 9, 9}
function MEWHIRLA(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID) or IEex_CompareActorAllegiances(sourceID, targetID) > -1 then return end
	local sourceData = IEex_GetActorShare(sourceID)
	local sourceX = IEex_ReadDword(sourceData + 0x6)
	local sourceY = IEex_ReadDword(sourceData + 0xA)
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
	local distX = math.abs(sourceX - targetX)
	local distY = math.floor(math.abs(sourceY - targetY) * 4 / 3)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local weaponRES = {"", ""}
	local weaponHand = {1, 2}
	local wearingLightArmor = true
	local equippedSlot = IEex_ReadByte(sourceData + 0x4BA4, 0x0)
	local currentAttack = IEex_ReadSignedByte(sourceData + 0x5636, 0x0)

	local numWeapons = 0
	if ex_record_attacks_made[sourceID] == nil then
		ex_record_attacks_made[sourceID] = {0, 0, 0, 0}
	end
	local extraAttacksMade = ex_record_attacks_made[sourceID][2]
	local extraMainhandAttacksMade = ex_record_attacks_made[sourceID][3]
	local currentAttackPenalty = 0
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter1 = IEex_ReadDword(eData + 0x1C)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
		if theopcode == 288 and theparameter2 == 241 then
			if thespecial == 5 or thespecial == 6 then
				numWeapons = numWeapons + 1
--[[
				if weaponRES[1] == "" then
					weaponRES[1] = IEex_ReadLString(eData + 0x94, 8)
				else
					weaponRES[2] = IEex_ReadLString(eData + 0x94, 8)
				end
--]]
			end

			if (theparameter1 >= 62 and theparameter1 <= 66) or theparameter1 == 68 then
				wearingLightArmor = false
			end
		end
	end)
	if bit.band(savingthrow, 0x10000) > 0 then
		if equippedSlot ~= 44 and equippedSlot ~= 46 and equippedSlot ~= 48 and equippedSlot ~= 50 then
			weaponRES[1] = IEex_GetItemSlotRES(sourceID, equippedSlot)
		elseif IEex_GetActorStat(sourceID, 101) > 0 then
			weaponRES[1] = IEex_GetItemSlotRES(sourceID, 10)
		end
	end
	if bit.band(savingthrow, 0x20000) > 0 then
		if IEex_GetActorStat(sourceID, 101) > 0 and (equippedSlot == 10 or (equippedSlot == 43 and IEex_GetItemSlotRES(sourceID, 10) == IEex_GetItemSlotRES(sourceID, 43))) then
			weaponRES[2] = IEex_GetItemSlotRES(sourceID, 10)
		elseif equippedSlot == 43 or equippedSlot == 45 or equippedSlot == 47 or equippedSlot == 49 then
			weaponRES[2] = IEex_GetItemSlotRES(sourceID, equippedSlot + 1)
		elseif equippedSlot == 44 or equippedSlot == 46 or equippedSlot == 48 or equippedSlot == 50 then
			weaponRES[2] = IEex_GetItemSlotRES(sourceID, equippedSlot)
		end
	end
	if bit.band(savingthrow, 0x30000) == 0 then
		weaponRES[1] = IEex_ReadLString(effectData + 0x18, 8)
		local attackPenaltyIncrement = 5
		if IEex_GetActorStat(sourceID, 101) > 0 and equippedSlot == 10 then
			attackPenaltyIncrement = 3
		end
		if weaponRES[1] == "" then
			if numWeapons >= 2 and currentAttack == IEex_GetActorStat(sourceID, 8) then
--				currentAttackPenalty = extraAttacksMade * attackPenaltyIncrement
				if equippedSlot == 43 or equippedSlot == 45 or equippedSlot == 47 or equippedSlot == 49 then
					weaponRES[2] = IEex_GetItemSlotRES(sourceID, equippedSlot + 1)
				elseif IEex_GetActorStat(sourceID, 101) > 0 and (equippedSlot == 10 or IEex_GetItemSlotRES(sourceID, 10) == IEex_GetItemSlotRES(sourceID, 43)) then
					weaponRES[2] = IEex_GetItemSlotRES(sourceID, 10)
				end
			elseif currentAttack >= 1 then
				currentAttackPenalty = (currentAttack - 1) * attackPenaltyIncrement
				if numWeapons >= 2 and currentAttack == IEex_GetActorStat(sourceID, 8) - 1 then
--					currentAttackPenalty = currentAttackPenalty + extraMainhandAttacksMade * attackPenaltyIncrement
				elseif numWeapons < 2 then
--					currentAttackPenalty = currentAttackPenalty + extraAttacksMade * attackPenaltyIncrement
				end
				weaponRES[1] = IEex_GetItemSlotRES(sourceID, equippedSlot)
			else
				weaponRES[1] = parent_resource
			end
		end
	end
	local dualWielding = false
	local dualWieldingPenalty = {0, 0}
--	if weaponRES[1] ~= "" and weaponRES[2] ~= "" then
	if numWeapons >= 2 then
		dualWielding = true
		dualWieldingPenalty = {6, 10}
		local resWrapper = IEex_DemandRes(weaponRES[2], "ITM")
		if resWrapper:isValid() then
			local itemData = resWrapper:getData()
			local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
			if itemType == 16 or itemType == 19 then
				dualWieldingPenalty[1] = dualWieldingPenalty[1] - 2
				dualWieldingPenalty[2] = dualWieldingPenalty[2] - 2
			end
		end
		resWrapper:free()
		if IEex_GetActorStat(sourceID, 103) > 0 and wearingLightArmor then
			dualWieldingPenalty[1] = dualWieldingPenalty[1] - 2
			dualWieldingPenalty[2] = dualWieldingPenalty[2] - 6
		else
			if bit.band(IEex_ReadDword(sourceData + 0x75C), 0x2) > 0 then
				dualWieldingPenalty[1] = dualWieldingPenalty[1] - 2
				dualWieldingPenalty[2] = dualWieldingPenalty[2] - 2
			end
			if bit.band(IEex_ReadDword(sourceData + 0x764), 0x40) > 0 then
				dualWieldingPenalty[2] = dualWieldingPenalty[2] - 4
			end
		end
	end
	local spriteHands = 2
	local animation = IEex_ReadDword(sourceData + 0x5C4)
	if extra_hands[animation] ~= nil then
		spriteHands = extra_hands[animation]
	end
	if spriteHands == 4 then
		if weaponRES[2] == "" then
			weaponRES = {weaponRES[1], weaponRES[1], weaponRES[1], weaponRES[1]}
			weaponHand = {1, 1, 1, 1}
		else
			weaponRES = {weaponRES[1], weaponRES[1], weaponRES[2], weaponRES[2]}
			weaponHand = {1, 1, 2, 2}
		end
	elseif spriteHands == 6 then
		if weaponRES[2] == "" then
			weaponRES = {weaponRES[1], weaponRES[1], weaponRES[1], weaponRES[1], weaponRES[1], weaponRES[1]}
			weaponHand = {1, 1, 1, 1, 1, 1}
		else
			weaponRES = {weaponRES[1], weaponRES[1], weaponRES[1], weaponRES[2], weaponRES[2], weaponRES[2]}
			weaponHand = {1, 1, 1, 2, 2, 2}
		end
	end
	local numAttacks = spriteHands
	local hand = 1
	while hand <= numAttacks do
		local res = weaponRES[hand]
		local resWrapper = IEex_DemandRes(res, "ITM")
		if resWrapper:isValid() then
			local itemData = resWrapper:getData()
			local proficiencyFeat = 0
			local isTwoHanded = (bit.band(IEex_ReadDword(itemData + 0x18), 0x2) > 0)
			local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
			if ex_item_type_proficiency[itemType] ~= nil then
				proficiencyFeat = ex_item_type_proficiency[itemType]
			end
			local criticalHitBonus = 0
			local baseCriticalMultiplier = 2
			if ex_item_type_critical[itemType] ~= nil then
				criticalHitBonus = ex_item_type_critical[itemType][1]
				baseCriticalMultiplier = ex_item_type_critical[itemType][2]
			end
			local effectOffset = IEex_ReadDword(itemData + 0x6A)
			local numHeaders = IEex_ReadWord(itemData + 0x68, 0x0)
			for header = 1, numHeaders, 1 do
				local offset = itemData + 0x4A + header * 0x38
				local headerFlags = IEex_ReadDword(offset + 0x26)
--				local itemRange = 20 * IEex_ReadWord(offset + 0xE, 0x0) + 40
				local itemRange = 16 * IEex_ReadWord(offset + 0xE, 0x0) + 38
				local whirlwindAttackFeatID = ex_feat_name_id["ME_WHIRLWIND_ATTACK"]
				if bit.band(savingthrow, 0x2000000) > 0 and whirlwindAttackFeatID ~= nil and IEex_ReadByte(sourceData + 0x744 + whirlwindAttackFeatID, 0x0) >= 2 then
					itemRange = itemRange + 32
				end
				local itemDamageType = IEex_ReadWord(offset + 0x1C, 0x0)
				if IEex_ReadByte(offset, 0x0) == 1 and ((distX <= itemRange and distY <= itemRange) or bit.band(savingthrow, 0x1000000) == 0) then
					local attackRoll = math.random(20) + IEex_GetActorStat(sourceID, 32)
					if attackRoll > 20 then
						attackRoll = 20
					elseif attackRoll < 1 then
						attackRoll = 1
					end
					local hit = 0
					local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
					local sourceStateValue = bit.bor(IEex_ReadDword(sourceData + 0x5BC), IEex_ReadDword(sourceData + 0x920))
					local concealment = 0
					if bit.band(stateValue, 0x20000000) > 0 then
						concealment = 20
					end
					if (bit.band(stateValue, 0x10) > 0 and IEex_GetActorStat(sourceID, 81) == 0) or bit.band(sourceStateValue, 0x40000) > 0 then
						concealment = 50
					end
					if bit.band(stateValue, 0xE9) > 0 or IEex_ReadSignedWord(offset + 0x14, 0x0) == 32767 then
						hit = 5
					elseif IEex_GetActorSpellState(sourceID, 59) and math.random(100) <= 20 then
						IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = 18352,
["source_id"] = sourceID
})
					elseif IEex_GetActorSpellState(targetID, 59) and math.random(100) <= 50 then
						IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = 18353,
["source_id"] = targetID
})
					else
						local concealed = false
						if math.random(100) <= concealment then
							concealed = true
						end
						if concealment > 0 and bit.band(IEex_ReadDword(sourceData + 0x75C), 0x40) > 0 then
							if not concealed or math.random(100) > concealment then
								IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = ex_tra_55390,
["source_id"] = sourceID
})
								concealed = false
							else
								IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = ex_tra_55391,
["source_id"] = sourceID
})
							end
						end
						if concealed then
							IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = ex_tra_55392,
["source_id"] = sourceID
})
						else
							local attackBonus = IEex_GetActorBaseAttackBonus(sourceID) + IEex_GetActorStat(sourceID, 7) + IEex_ReadSignedWord(offset + 0x14, 0x0) - IEex_ReadSignedWord(effectData + 0x44, 0x0) - currentAttackPenalty
							if proficiencyFeat > 0 then
--								attackBonus = attackBonus + tonumber(IEex_2DAGetAtStrings("WSPECIAL", "HIT", tostring(IEex_ReadByte(sourceData + ex_feat_id_offset[proficiencyFeat], 0x0))))
								attackBonus = attackBonus + ex_proficiency_attack[IEex_ReadByte(sourceData + ex_feat_id_offset[proficiencyFeat], 0x0)]
							end
							if IEex_ReadByte(sourceData + 0x24, 0x0) >= 200 then
								attackBonus = attackBonus + ex_difficulty_attack_bonus[IEex_GetGameDifficulty()]
							end
							if IEex_GetActorStat(sourceID, 103) > 0 then
								local favoredEnemyBonus = 0
								local enemyRace = IEex_ReadByte(creatureData + 0x26, 0x0)
								for i = 7, 0, -1 do
									local favoredEnemy = IEex_ReadByte(sourceData + 0x7F7 + i, 0x0)
									if favoredEnemy ~= 255 then
										favoredEnemyBonus = favoredEnemyBonus + 1
									end
									if favoredEnemy == enemyRace then
										attackBonus = attackBonus + favoredEnemyBonus
									end
								end
							end
							if weaponHand[hand] == 1 then
								attackBonus = attackBonus - dualWieldingPenalty[1] + IEex_ReadSignedByte(sourceData + 0x9F8, 0x0)
							else
								attackBonus = attackBonus - dualWieldingPenalty[2] + IEex_ReadSignedByte(sourceData + 0x9FC, 0x0)
							end
							if bit.band(headerFlags, 0x20000) > 0 then
								criticalHitBonus = criticalHitBonus + 1
							end
							if bit.band(IEex_ReadDword(sourceData + 0x75C), 0x40000000) > 0 then
								criticalHitBonus = criticalHitBonus + 1
							end
--							if IEex_GetActorSpellState(sourceID, 56) then
								criticalHitBonus = criticalHitBonus + IEex_ReadSignedByte(sourceData + 0x936, 0x0)
--							end
							local attackStatBonus = 0
							if bit.band(headerFlags, 0x1) > 0 then
								attackStatBonus = math.floor((IEex_GetActorStat(sourceID, 36) - 10) / 2)
							end
							if (itemType == 16 or itemType == 19) and bit.band(IEex_ReadDword(sourceData + 0x764), 0x80) > 0 then
								local dexterityBonus = math.floor((IEex_GetActorStat(sourceID, 40) - 10) / 2)
								if dexterityBonus > attackStatBonus then
									attackStatBonus = dexterityBonus
								end
							end
							attackBonus = attackBonus + attackStatBonus
							for i = 1, 5, 1 do
								if IEex_GetActorSpellState(sourceID, i + 75) or IEex_GetActorSpellState(sourceID, i + 80) then
									attackBonus = attackBonus - i
								end
							end
							local armorClassList = IEex_GetActorArmorClass(targetID)
							local ac = armorClassList[1]
							local acslashing = armorClassList[2]
							local acpiercing = armorClassList[3]
							local acbludgeoning = armorClassList[4]
							local acmissile = armorClassList[5]
							if itemDamageType == 3 or (itemDamageType == 7 and acslashing <= acpiercing) or (itemDamageType == 8 and acslashing <= acbludgeoning) then
								ac = ac + acslashing
							elseif itemDamageType == 1 or (itemDamageType == 6 and acpiercing <= acbludgeoning) or (itemDamageType == 7 and acpiercing <= acslashing) then
								ac = ac + acpiercing
							elseif itemDamageType == 2 or (itemDamageType == 6 and acbludgeoning <= acpiercing) or (itemDamageType == 8 and acbludgeoning <= acslashing) then
								ac = ac + acbludgeoning
							elseif itemDamageType == 4 or itemDamageType == 9 then
								ac = ac + acmissile
							end
							if attackRoll == 1 then
								hit = 4
							elseif attackRoll == 20 or attackRoll + attackBonus >= ac then
								hit = 1
							else
								hit = 2
							end
							if weaponHand[hand] == 2 then
								if bit.band(savingthrow, 0x30000) == 0 then
									IEex_SetToken("EXWHACTION" .. ex_whirla_index, IEex_FetchString(14643) .. "1 (" .. IEex_FetchString(733) .. ")")
								else
									IEex_SetToken("EXWHACTION" .. ex_whirla_index, IEex_FetchString(14643) .. "(" .. IEex_FetchString(733) .. ")")
								end
							else
								if bit.band(savingthrow, 0x30000) == 0 then
									IEex_SetToken("EXWHACTION" .. ex_whirla_index, IEex_FetchString(14643) .. currentAttack .. " ")
								else
									IEex_SetToken("EXWHACTION" .. ex_whirla_index, IEex_FetchString(14643))
								end
							end
							IEex_SetToken("EXWHROLL" .. ex_whirla_index, attackRoll)
							if attackBonus >= 0 then
								IEex_SetToken("EXWHBONUS" .. ex_whirla_index, "+ " .. attackBonus)
							else
								IEex_SetToken("EXWHBONUS" .. ex_whirla_index, "- " .. math.abs(attackBonus))
							end
							IEex_SetToken("EXWHTOTAL" .. ex_whirla_index, attackRoll + attackBonus)
							IEex_SetToken("EXWHHITMISS" .. ex_whirla_index, IEex_FetchString(16459 + hit))
							IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = ex_whirla[ex_whirla_index],
["source_id"] = sourceID
})
							if ex_whirla_index == 40 then
								ex_whirla_index = 1
							else
								ex_whirla_index = ex_whirla_index + 1
							end
							if attackRoll >= 20 - criticalHitBonus and bit.band(IEex_ReadByte(creatureData + 0x89F, 0x0), 0x2) == 0 then
								local threatRoll = math.random(20) + IEex_GetActorStat(sourceID, 32)
								if threatRoll > 20 then
									threatRoll = 20
								elseif threatRoll < 1 then
									threatRoll = 1
								end
								if threatRoll == 20 or (threatRoll >= 2 and threatRoll + attackBonus >= ac) then
									hit = 3
								end
								if weaponHand[hand] == 2 then
									if bit.band(savingthrow, 0x30000) == 0 then
										IEex_SetToken("EXWHACTION" .. ex_whirla_index, IEex_FetchString(39874) .. " 1 (" .. IEex_FetchString(733) .. ")")
									else
										IEex_SetToken("EXWHACTION" .. ex_whirla_index, IEex_FetchString(39874) .. " (" .. IEex_FetchString(733) .. ")")
									end
								else
									if bit.band(savingthrow, 0x30000) == 0 then
										IEex_SetToken("EXWHACTION" .. ex_whirla_index, IEex_FetchString(39874) .. " " .. currentAttack .. " ")
									else
										IEex_SetToken("EXWHACTION" .. ex_whirla_index, IEex_FetchString(39874) .. " ")
									end
								end
								IEex_SetToken("EXWHROLL" .. ex_whirla_index, threatRoll)
								if attackBonus >= 0 then
									IEex_SetToken("EXWHBONUS" .. ex_whirla_index, "+ " .. attackBonus)
								else
									IEex_SetToken("EXWHBONUS" .. ex_whirla_index, "- " .. math.abs(attackBonus))
								end
								IEex_SetToken("EXWHTOTAL" .. ex_whirla_index, threatRoll + attackBonus)
								if hit == 3 then
									IEex_SetToken("EXWHHITMISS" .. ex_whirla_index, IEex_FetchString(16462))
								else
									IEex_SetToken("EXWHHITMISS" .. ex_whirla_index, IEex_FetchString(33752))
								end
								IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = ex_whirla[ex_whirla_index],
["source_id"] = sourceID
})
								if ex_whirla_index == 40 then
									ex_whirla_index = 1
								else
									ex_whirla_index = ex_whirla_index + 1
								end
							end
						end
					end

					if hit == 1 or hit == 3 or hit == 5 then
						if itemDamageType > 0 then
							local newparameter2 = 0
							if itemDamageType == 1 or itemDamageType == 4 then
								newparameter2 = 0x100000
							elseif itemDamageType == 3 or itemDamageType == 7 or itemDamageType == 8 then
								newparameter2 = 0x1000000
							elseif itemDamageType == 5 then
								newparameter2 = 0x8000000
							end
							local newparameter4 = 0
							if hit == 3 then
--[[
								local criticalMultiplier = baseCriticalMultiplier
								local effectOffset = IEex_ReadDword(itemData + 0x6A)
								local numGlobalEffects = IEex_ReadWord(itemData + 0x70, 0x0)
								for i = 0, numGlobalEffects - 1, 1 do
									local offset = itemData + effectOffset + i * 0x30
									local theopcode = IEex_ReadWord(offset, 0x0)
									local theparameter2 = IEex_ReadDword(offset + 0x8)
									local thesavingthrow = IEex_ReadDword(offset + 0x24)
									if theopcode == 288 and theparameter2 == 195 and bit.band(thesavingthrow, 0x10000) > 0 then
										local theparameter1 = IEex_ReadDword(offset + 0x4)
										criticalMultiplier = criticalMultiplier + theparameter1
									end
								end
								IEex_IterateActorEffects(sourceID, function(eData)
									local theopcode = IEex_ReadDword(eData + 0x10)
									local theparameter2 = IEex_ReadDword(eData + 0x20)
									local thesavingthrow = IEex_ReadDword(eData + 0x40)
									local thespecial = IEex_ReadDword(eData + 0x48)
									if theopcode == 288 and theparameter2 == 195 and bit.band(thesavingthrow, 0x10000) == 0 and (thespecial == -1 or thespecial == itemType) then
										local theparameter1 = IEex_ReadDword(eData + 0x1C)
										criticalMultiplier = criticalMultiplier + theparameter1
									end
								end)
--]]
								newparameter4 = baseCriticalMultiplier
							end
							local bonusStat = 0
							local bonusStatMultiplier = 0
							local bonusStatDivisor = 0
							local weaponEnchantment = IEex_ReadDword(itemData + 0x60)
							if bit.band(headerFlags, 0x1) > 0 then
								bonusStat = 36
								if isTwoHanded and (equippedSlot ~= 43 or IEex_GetItemSlotRES(sourceID, 10) ~= IEex_GetItemSlotRES(sourceID, 43)) then
									bonusStatMultiplier = 3
									bonusStatDivisor = 2
								elseif hand == 2 then
									bonusStatMultiplier = 1
									bonusStatDivisor = 2
								end
							end
							local effectFlags = 0x2020000
--							if weaponRES[1] == weaponRES[2] then
								effectFlags = 0x2024000
--							end
							local damageBonus = IEex_ReadSignedByte(offset + 0x1A, 0x0)
							if weaponHand[hand] == 1 then
								damageBonus = damageBonus + IEex_ReadDword(sourceData + 0xA00)
							else
								damageBonus = damageBonus + IEex_ReadDword(sourceData + 0xA04)
							end
							if bit.band(savingthrow, 0x10000000) > 0 then
								damageBonus = damageBonus - IEex_ReadSignedWord(effectData + 0x46, 0x0)
							end
							IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = damageBonus + (IEex_ReadByte(offset + 0x16, 0x0) * 0x100) + (IEex_ReadByte(offset + 0x18, 0x0) * 0x10000),
["parameter2"] = newparameter2,
["parameter4"] = newparameter4,
["savingthrow"] = effectFlags,
["special"] = bonusStat + (bonusStatMultiplier * 0x100) + (bonusStatDivisor * 0x10000) + (weaponEnchantment * 0x1000000),
["resource"] = "EXDAMAGE",
["parent_resource"] = res,
["internal_flags"] = bit.bor(internalFlags, 0x40),
["source_id"] = sourceID
})
						end
						local probabilityRoll = math.random(100) - 1
						local firstEffectIndex = IEex_ReadWord(offset + 0x20, 0x0)
						local headerNumEffects = IEex_ReadWord(offset + 0x1E, 0x0)
						local extraAttackChance = 0
						for headerEffect = 1, headerNumEffects, 1 do
							local headerEffectOffset = itemData + effectOffset + 0x30 * firstEffectIndex + 0x30 * (headerEffect - 1)
							local effopcode = IEex_ReadWord(headerEffectOffset, 0x0)
							local effprobability1 = IEex_ReadByte(headerEffectOffset + 0x12, 0x0)
							local effprobability2 = IEex_ReadByte(headerEffectOffset + 0x13, 0x0)
							local effsavingthrow = IEex_ReadDword(headerEffectOffset + 0x24)
							if effopcode == 442 then
								extraAttackChance = extraAttackChance + effprobability1 - effprobability2 + 1
							elseif probabilityRoll <= effprobability1 and probabilityRoll >= effprobability2 and bit.band(effsavingthrow, 0x40) == 0 then
								local effTargetID = targetID
								local effTargetX = targetX
								local effTargetY = targetY
								if IEex_ReadByte(headerEffectOffset + 0x2, 0x0) == 1 then
									effTargetID = sourceID
									effTargetX = sourceX
									effTargetY = sourceY
								end
								local effpower = IEex_ReadByte(headerEffectOffset + 0x3, 0x0)
								local effparameter1 = IEex_ReadDword(headerEffectOffset + 0x4)
								local effparameter2 = IEex_ReadDword(headerEffectOffset + 0x8)
								local efftiming = IEex_ReadByte(headerEffectOffset + 0xC, 0x0)
								local effresist_dispel = IEex_ReadByte(headerEffectOffset + 0xD, 0x0)
								local effduration = IEex_ReadDword(headerEffectOffset + 0xE)
								local effresource = IEex_ReadLString(headerEffectOffset + 0x14, 8)
								local effdicenumber = IEex_ReadDword(headerEffectOffset + 0x1C)
								local effdicesize = IEex_ReadDword(headerEffectOffset + 0x20)
								local effsavebonus = IEex_ReadDword(headerEffectOffset + 0x28)
								local effspecial = IEex_ReadDword(headerEffectOffset + 0x2C)

								if effopcode == 12 then
									effopcode = 500
									if effdicenumber < 0 then
										effdicenumber = 0
									end
									if effdicesize < 0 then
										effdicesize = 0
									end
									effparameter1 = IEex_ReadByte(headerEffectOffset + 0x4, 0x0) + (effdicesize * 0x100) + (effdicenumber * 0x10000)
									efftiming = 0
									effduration = 0
									effresource = "EXDAMAGE"
									effdicenumber = 0
									effdicesize = 0
									effsavingthrow = bit.bor(effsavingthrow, 0x10000)
									if bit.band(effsavingthrow, 0x4) > 0 then
										effsavingthrow = bit.bor(effsavingthrow, 0x400)
									end
									if bit.band(effsavingthrow, 0x8) > 0 then
										effsavingthrow = bit.bor(effsavingthrow, 0x800)
									end
									if bit.band(effsavingthrow, 0x10) > 0 then
										effsavingthrow = bit.bor(effsavingthrow, 0x1000)
									end
									effsavingthrow = bit.band(effsavingthrow, 0xFFFFFFE3)
									if effopcode == 500 and weaponRES[1] == weaponRES[2] then
										effsavingthrow = bit.bor(effsavingthrow, 0x4000)
									end
									effspecial = 0
								end
								IEex_ApplyEffectToActor(effTargetID, {
	["opcode"] = effopcode,
	["target"] = 2,
	["timing"] = efftiming,
	["duration"] = effduration,
	["parameter1"] = effparameter1,
	["parameter2"] = effparameter2,
	["dicenumber"] = effdicenumber,
	["dicesize"] = effdicesize,
	["resource"] = effresource,
	["resist_dispel"] = effresist_dispel,
	["savingthrow"] = effsavingthrow,
	["savebonus"] = effsavebonus,
	["special"] = effspecial,
	["source_x"] = sourceX,
	["source_y"] = sourceY,
	["target_x"] = targetX,
	["target_y"] = targetY,
	["parent_resource"] = res,
	["internal_flags"] = bit.bor(internalFlags, 0x40),
	["source_id"] = sourceID
	})
							end
						end
						if hand <= spriteHands and math.random(100) <= extraAttackChance and bit.band(savingthrow, 0x40000000) == 0 then
							numAttacks = numAttacks + 1
							table.insert(weaponRES, res)
							table.insert(weaponHand, weaponHand[hand])
							IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["parameter1"] = 39846,
["source_id"] = sourceID
})
--[[
							local newsavingthrow = bit.bor(savingthrow, 0x40000000)
							if weaponHand[hand] == 1 then
								newsavingthrow = bit.band(savingthrow, 0xFFFDFFFF)
							else
								newsavingthrow = bit.band(savingthrow, 0xFFFEFFFF)
							end
							IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["savingthrow"] = newsavingthrow,
["resource"] = "MEWHIRLA",
["source_id"] = sourceID
})
--]]
						end
					end
				end
			end
			resWrapper:free()
		end
		hand = hand + 1
	end
end

function MEROTATE(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if IEex_ReadDword(effectData + 0x1C) > 0 and IEex_IsSprite(sourceID) then
		local sourceData = IEex_GetActorShare(sourceID)
--[[
		IEex_WriteWord(sourceData + 0x537C, -1)
		local orientation1 = IEex_ReadByte(sourceData + 0x5380, 0x0)
		IEex_WriteByte(sourceData + 0x537E, orientation1)
		IEex_WriteByte(sourceData + 0x5380, (orientation1 - 1) % 16)
--]]
		IEex_WriteWord(sourceData + 0x537C, 1)
		local orientation1 = IEex_ReadByte(sourceData + 0x5380, 0x0)
		IEex_WriteByte(sourceData + 0x537E, (orientation1 - 1) % 16)
--		IEex_WriteByte(sourceData + 0x5380, (orientation1 + 1) % 16)
	else
		IEex_WriteWord(creatureData + 0x537C, -1)
		local orientation1 = IEex_ReadByte(creatureData + 0x5380, 0x0)
		IEex_WriteByte(creatureData + 0x537E, orientation1)
		IEex_WriteByte(creatureData + 0x5380, (orientation1 - 1) % 16)
	end
end

function MESPIN(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MESPIN", 5) then return end
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local special = IEex_ReadDword(effectData + 0x44)
	local doSpin = true
	if bit.band(savingthrow, 0x80000) > 0 then
		IEex_WriteWord(creatureData + 0x476, 0)
	end
	if bit.band(savingthrow, 0x20000) > 0 then
		doSpin = false
		local animationSequence = IEex_ReadByte(creatureData + 0x50F4, 0x0)
		if bit.band(savingthrow, 0x20000) == 0 or animationSequence == special or (special == 0 and animationSequence >= 11 and animationSequence <= 13) then
			if bit.band(savingthrow, 0x2000000) > 0 then
				local itemRange = 40
				local numEnemiesInRange = 0
				local weaponRES = IEex_GetItemSlotRES(targetID, IEex_ReadByte(creatureData + 0x4BA4, 0x0))
				local weaponHeader = IEex_ReadByte(creatureData + 0x4BA6, 0x0)
				local resWrapper = IEex_DemandRes(weaponRES, "ITM")
				if resWrapper:isValid() then
					local itemData = resWrapper:getData()
					local offset = itemData + 0x82 + weaponHeader * 0x38
					itemRange = itemRange + 20 * IEex_ReadWord(offset + 0xE, 0x0)

					local whirlwindAttackFeatID = ex_feat_name_id["ME_WHIRLWIND_ATTACK"]
					if whirlwindAttackFeatID ~= nil and IEex_ReadByte(creatureData + 0x744 + whirlwindAttackFeatID, 0x0) >= 2 then
						itemRange = itemRange + 60
					end

				end
				resWrapper:free()
				local targetX, targetY = IEex_GetActorLocation(targetID)
				local ids = {}
				if IEex_ReadDword(creatureData + 0x12) > 0 then
					ids = IEex_GetIDArea(targetID, 0x31)
				end
				local closestDistance = 0x7FFFFFFF
				local possibleTargets = {}
				for k, currentID in ipairs(ids) do
					local currentShare = IEex_GetActorShare(currentID)
					if currentShare > 0 then
						local currentX = IEex_ReadDword(currentShare + 0x6)
						local currentY = IEex_ReadDword(currentShare + 0xA)
						local currentDistance = IEex_GetDistance(targetX, targetY, currentX, currentY)
						local states = IEex_ReadDword(currentShare + 0x5BC)
						local animation = IEex_ReadDword(currentShare + 0x5C4)
						local cea = IEex_CompareActorAllegiances(targetID, currentID)
						if currentDistance <= itemRange and cea == -1 and IEex_CheckActorLOSObject(targetID, currentID) and animation >= 0x1000 and (animation < 0xD000 or animation >= 0xE000) and bit.band(states, 0x800) == 0 and IEex_ReadByte(currentShare + 0x838, 0x0) == 0 then
							numEnemiesInRange = numEnemiesInRange + 1
						end
					end
				end
				if numEnemiesInRange >= 2 then
					doSpin = true
				end
			else
				doSpin = true
			end
		end
	end
	if not doSpin then return end
	local rotationAmount = IEex_ReadSignedWord(effectData + 0x18, 0x0)

	if rotationAmount == 0 then
		rotationAmount = 1
	end
	local newRotationDirection = IEex_ReadSignedWord(effectData + 0x1C, 0x0)
	if newRotationDirection ~= 1 then
		newRotationDirection = -1
	end
	local currentDirection = IEex_ReadByte(creatureData + 0x5380, 0x0)
	IEex_WriteWord(creatureData + 0x537C, newRotationDirection)
	IEex_WriteByte(creatureData + 0x537E, (currentDirection + rotationAmount * newRotationDirection) % 16)
end

function MESPELL(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
--	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if spellRES ~= "" then
		local newTiming = 0
		local newDuration = 0
		if bit.band(savingthrow, 0x4000000) > 0 then
			newTiming = 6
			newDuration = IEex_GetGameTick() + IEex_ReadDword(effectData + 0x44)
		end
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = newTiming,
["duration"] = newDuration,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["target_x"] = IEex_ReadDword(effectData + 0x84),
["target_y"] = IEex_ReadDword(effectData + 0x88),
["source_target"] = targetID,
["source_id"] = IEex_ReadDword(effectData + 0x10C),
})
	end
end

ex_splatk_index = 1
function MESPLATK(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID) then return end
	local sourceData = IEex_GetActorShare(sourceID)
	local sourceX = IEex_ReadDword(sourceData + 0x6)
	local sourceY = IEex_ReadDword(sourceData + 0xA)
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
	local distX = math.abs(sourceX - targetX)
	local distY = math.floor(math.abs(sourceY - targetY) * 4 / 3)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local isRanged = (bit.band(savingthrow, 0x10000) > 0)
	local ignoreIfNotUndead = (bit.band(savingthrow, 0x10000000) > 0)
	if ignoreIfNotUndead and IEex_ReadByte(creatureData + 0x25, 0x0) ~= 4 then return end
	local currentAttackPenalty = 0
	local proficiencyFeat = ex_melee_touch_attack_proficiency_feat
	if isRanged then
		proficiencyFeat = ex_ranged_touch_attack_proficiency_feat
	end
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	local criticalHitBonus = 0
	local baseCriticalMultiplier = 2
	local attackRoll = math.random(20) + IEex_GetActorStat(sourceID, 32)
	if attackRoll > 20 then
		attackRoll = 20
	elseif attackRoll < 1 then
		attackRoll = 1
	end
	local hit = 0
	local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
	local sourceStateValue = bit.bor(IEex_ReadDword(sourceData + 0x5BC), IEex_ReadDword(sourceData + 0x920))
	local concealment = 0
	if bit.band(stateValue, 0x20000000) > 0 then
		concealment = 20
	end
	if (bit.band(stateValue, 0x10) > 0 and IEex_GetActorStat(sourceID, 81) == 0) or bit.band(sourceStateValue, 0x40000) > 0 then
		concealment = 50
	end
	if bit.band(stateValue, 0xE9) > 0 or sourceID == targetID then
		hit = 5
	elseif IEex_GetActorSpellState(sourceID, 59) and math.random(100) <= 20 then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = 18352,
["source_id"] = sourceID
})
		return
	elseif IEex_GetActorSpellState(targetID, 59) and math.random(100) <= 50 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = 18353,
["source_id"] = targetID
})
		return
	else
		local concealed = false
		if math.random(100) <= concealment then
			concealed = true
		end
		if concealment > 0 and bit.band(IEex_ReadDword(sourceData + 0x75C), 0x40) > 0 then
			if not concealed or math.random(100) > concealment then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = ex_tra_55390,
["source_id"] = sourceID
})
			concealed = false
		else
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = ex_tra_55391,
["source_id"] = sourceID
})
			end
		end
		if concealed then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = ex_tra_55392,
["source_id"] = sourceID
})
			return
		end
		local attackBonus = IEex_GetActorBaseAttackBonus(sourceID) + IEex_GetActorStat(sourceID, 7) - currentAttackPenalty
		if proficiencyFeat > 0 then
			attackBonus = attackBonus + tonumber(IEex_2DAGetAtStrings("WSPECIAL", "HIT", tostring(IEex_ReadByte(sourceData + ex_feat_id_offset[proficiencyFeat], 0x0))))
--								attackBonus = attackBonus + ex_proficiency_attack[IEex_ReadByte(sourceData + ex_feat_id_offset[proficiencyFeat], 0x0)]
		end
		if IEex_ReadByte(sourceData + 0x24, 0x0) >= 200 then
			attackBonus = attackBonus + ex_difficulty_attack_bonus[IEex_GetGameDifficulty()]
		end
		if IEex_GetActorStat(sourceID, 103) > 0 then
			local favoredEnemyBonus = 0
			local enemyRace = IEex_ReadByte(creatureData + 0x26, 0x0)
			for i = 7, 0, -1 do
				local favoredEnemy = IEex_ReadByte(sourceData + 0x7F7 + i, 0x0)
				if favoredEnemy ~= 255 then
					favoredEnemyBonus = favoredEnemyBonus + 1
				end
				if favoredEnemy == enemyRace then
					attackBonus = attackBonus + favoredEnemyBonus
				end
			end
		end
		if bit.band(IEex_ReadDword(sourceData + 0x75C), 0x40000000) > 0 then
			criticalHitBonus = criticalHitBonus + 1
		end
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if theopcode == 500 and theresource == "MECRIT" and thespecial <= 0 then
				if (bit.band(thesavingthrow, 0x50000) == 0 or not isRanged) and (bit.band(thesavingthrow, 0x20000) == 0 or isRanged) then
					criticalHitBonus = criticalHitBonus + theparameter1
				end
			end
		end)
		if IEex_GetActorSpellState(sourceID, 56) then
			criticalHitBonus = criticalHitBonus + 4
		end
--		criticalHitBonus = criticalHitBonus + IEex_ReadSignedByte(sourceData + 0x936, 0x0)
		local attackStat = 0
		if bit.band(savingthrow, 0x20000) == 0 then
			attackStat = ex_melee_touch_attack_roll_modifier_stat
			if isRanged then
				attackStat = ex_ranged_touch_attack_roll_modifier_stat
			end
			if ex_spell_touch_attack_rolls_use_spellcasting_ability_modifier then
				if casterClass == 11 then
					attackStat = 38
				elseif casterClass == 3 or casterClass == 4 or casterClass == 6 or casterClass == 7 or casterClass == 8 then
					attackStat = 39
				elseif casterClass == 2 or casterClass == 10 then
					attackStat = 42
				end
			end
		end
		local attackStatBonus = 0
		if attackStat >= 36 and attackStat <= 42 then
			attackStatBonus = math.floor((IEex_GetActorStat(sourceID, attackStat) - 10) / 2)
		elseif attackStat > 0 then
			attackStatBonus = IEex_GetActorStat(sourceID, attackStat)
		end
		attackStat = IEex_ReadByte(effectData + 0x44, 0x0)
		local attackStatMultiplier = IEex_ReadSignedByte(effectData + 0x45, 0x0)
		if attackStatMultiplier == 0 then
			attackStatMultiplier = 1
		end
		local attackStatDivisor = IEex_ReadSignedByte(effectData + 0x46, 0x0)
		if attackStatDivisor == 0 then
			attackStatDivisor = 1
		end
		if attackStat >= 36 and attackStat <= 42 then
			attackStatBonus = attackStatBonus + math.floor(((IEex_GetActorStat(sourceID, attackStat) - 10) / 2) * attackStatMultiplier / attackStatDivisor)
		elseif attackStat > 0 then
			attackStatBonus = attackStatBonus + math.floor(IEex_GetActorStat(sourceID, attackStat) * attackStatMultiplier / attackStatDivisor)
		end
		attackBonus = attackBonus + attackStatBonus
		if bit.band(savingthrow, 0x40000) == 0 then
			attackBonus = attackBonus + IEex_ReadByte(effectData + 0x47, 0x0)
		else
			IEex_IterateActorEffects(targetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				local thespecial = IEex_ReadDword(eData + 0x48)
				if theopcode == 288 and theparameter2 == 241 and (theparameter1 == 62 or theparameter1 == 63 or theparameter1 == 64 or theparameter1 == 65 or theparameter1 == 68) then
					attackBonus = attackBonus + IEex_ReadByte(effectData + 0x47, 0x0)
				end
			end)
		end
		if not isRanged and ex_melee_touch_attacks_use_power_attack then
			for i = 1, 5, 1 do
				if IEex_GetActorSpellState(sourceID, i + 75) or IEex_GetActorSpellState(sourceID, i + 80) then
					attackBonus = attackBonus - i
				end
			end
		end
		if ex_pnp_ranged_penalty_without_precise_shot_to_avoid_hitting_ally and isRanged and bit.band(IEex_ReadDword(sourceData + 0x760), 0x10000) == 0 then
			local ids = {}
			if IEex_ReadDword(creatureData + 0x12) > 0 then
				ids = IEex_GetIDArea(targetID, 0x31)
			end
			local applyPreciseShotPenalty = false
			for k, currentID in ipairs(ids) do
				local currentShare = IEex_GetActorShare(currentID)
				if currentShare > 0 then
					local currentX = IEex_ReadDword(currentShare + 0x6)
					local currentY = IEex_ReadDword(currentShare + 0xA)
					local currentDistance = IEex_GetDistanceIsometric(targetX, targetY, currentX, currentY)
					local cea = IEex_CompareActorAllegiances(targetID, currentID)
					if cea == 1 and currentID ~= targetID and currentID ~= actionTargetID and currentDistance <= 100 then
						applyPreciseShotPenalty = true
					end
				end
			end
			if applyPreciseShotPenalty then
				attackBonus = attackBonus - 4
			end
		end
		if not isRanged then
			local sourceVisualHeight = IEex_ReadDword(sourceData + 0xE)
			local targetVisualHeight = IEex_ReadDword(creatureData + 0xE)
			if math.abs(targetVisualHeight - sourceVisualHeight) > 60 then
				attackBonus = attackBonus - 20
			end
		end
		local armorClassList = IEex_GetActorArmorClass(targetID)
		local ac = armorClassList[1] - IEex_GetActorStat(targetID, 238) - IEex_GetActorStat(targetID, 240)
--[[
		local acslashing = armorClassList[2]
		local acpiercing = armorClassList[3]
		local acbludgeoning = armorClassList[4]
		local acmissile = armorClassList[5]
		if itemDamageType == 3 or (itemDamageType == 7 and acslashing <= acpiercing) or (itemDamageType == 8 and acslashing <= acbludgeoning) then
			ac = ac + acslashing
		elseif itemDamageType == 1 or (itemDamageType == 6 and acpiercing <= acbludgeoning) or (itemDamageType == 7 and acpiercing <= acslashing) then
			ac = ac + acpiercing
		elseif itemDamageType == 2 or (itemDamageType == 6 and acbludgeoning <= acpiercing) or (itemDamageType == 8 and acbludgeoning <= acslashing) then
			ac = ac + acbludgeoning
		elseif itemDamageType == 4 or itemDamageType == 9 then
			ac = ac + acmissile
		end
--]]
		if attackRoll == 1 then
			hit = 4
		elseif attackRoll == 20 or attackRoll + attackBonus >= ac then
			hit = 1
		else
			hit = 2
		end
		if isRanged then
			IEex_SetToken("EXWHACTION" .. ex_whirla_index, IEex_FetchString(ex_tra_55376))
		else
			IEex_SetToken("EXWHACTION" .. ex_whirla_index, IEex_FetchString(ex_tra_55375))
		end
		IEex_SetToken("EXWHROLL" .. ex_whirla_index, attackRoll)
		if attackBonus >= 0 then
			IEex_SetToken("EXWHBONUS" .. ex_whirla_index, "+ " .. attackBonus)
		else
			IEex_SetToken("EXWHBONUS" .. ex_whirla_index, "- " .. math.abs(attackBonus))
		end
		IEex_SetToken("EXWHTOTAL" .. ex_whirla_index, attackRoll + attackBonus)
		IEex_SetToken("EXWHHITMISS" .. ex_whirla_index, IEex_FetchString(16459 + hit))
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = ex_whirla[ex_whirla_index],
["source_id"] = sourceID
})
		if ex_whirla_index == 40 then
			ex_whirla_index = 1
		else
			ex_whirla_index = ex_whirla_index + 1
		end
		if attackRoll >= 20 - criticalHitBonus and bit.band(IEex_ReadByte(creatureData + 0x89F, 0x0), 0x2) == 0 then
			local threatRoll = math.random(20) + IEex_GetActorStat(sourceID, 32)
			if threatRoll > 20 then
				threatRoll = 20
			elseif threatRoll < 1 then
				threatRoll = 1
			end
			if threatRoll == 20 or (threatRoll >= 2 and threatRoll + attackBonus >= ac) then
				hit = 3
			end
			IEex_SetToken("EXWHACTION" .. ex_whirla_index, IEex_FetchString(39874) .. " ")
			IEex_SetToken("EXWHROLL" .. ex_whirla_index, threatRoll)
			if attackBonus >= 0 then
				IEex_SetToken("EXWHBONUS" .. ex_whirla_index, "+ " .. attackBonus)
			else
				IEex_SetToken("EXWHBONUS" .. ex_whirla_index, "- " .. math.abs(attackBonus))
			end
			IEex_SetToken("EXWHTOTAL" .. ex_whirla_index, threatRoll + attackBonus)
			if hit == 3 then
				IEex_SetToken("EXWHHITMISS" .. ex_whirla_index, IEex_FetchString(16462))
			else
				IEex_SetToken("EXWHHITMISS" .. ex_whirla_index, IEex_FetchString(33752))
			end
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = ex_whirla[ex_whirla_index],
["source_id"] = sourceID
})
			if ex_whirla_index == 40 then
				ex_whirla_index = 1
			else
				ex_whirla_index = ex_whirla_index + 1
			end
		end
	end
	if hit == 1 or hit == 3 or hit == 5 then
		local newInternalFlags = internalFlags
		if isRanged then
			newInternalFlags = bit.bor(newInternalFlags, 0x2000)
		else
			newInternalFlags = bit.bor(newInternalFlags, 0x1000)
		end
		if hit == 3 then
			newInternalFlags = bit.bor(newInternalFlags, 0x8000)
		end
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["savebonus"] = IEex_ReadDword(effectData + 0x40),
["resource"] = spellRES,
["parent_resource"] = parent_resource,
["casterlvl"] = casterlvl,
["internal_flags"] = newInternalFlags,
["source_id"] = sourceID
})
	end
end

onhitspells = {
[1] = "USOHTEST",
[51] = "USPOISOW",
[5020] = "USCLEA20",
[5050] = "USCLEA50",
[5100] = "USCLEA00",
}

exhitspells = {
[1] = {[10001] = "USSERW10", [10002] = "USSLAY20"},
[2] = {[10003] = "USCRIW20", [10004] = "USDEST30"},
[1001] = {[11001] = "USSNEAKP"},
[2001] = {[12001] = "USBRACTC", [12002] = "USHFBCTC", [12003] = "USQUIVPA", [12004] = "USSTUNAT",},
}

function MEONHIT(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if bit.band(internalFlags, 0x4000000) > 0 then return end
	local index = IEex_ReadDword(effectData + 0x1C)
	local headerType = IEex_ReadDword(effectData + 0x44)
	if headerType == 1 then
		if ex_attopp_opportunist[targetID] == nil then
			ex_attopp_opportunist[targetID] = {[sourceID] = IEex_GetGameTick()}
		else
			ex_attopp_opportunist[targetID][sourceID] = IEex_GetGameTick()
		end
	end
	local sourceExpired = {}
	local onHitEffectList = {}
--	if IEex_GetActorSpellState(sourceID, 225) then
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 225 and bit.band(thesavingthrow, 0x100000) == 0 and bit.band(thesavingthrow, 0x800000) == 0 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local matchHeader = IEex_ReadWord(eData + 0x48, 0x0)
				local spellRES = IEex_ReadLString(eData + 0x30, 8)
				local thesourceid = IEex_ReadDword(eData + 0x110)
				if theparameter1 == index and spellRES ~= "" and (matchHeader == 0 or matchHeader == headerType) and (bit.band(thesavingthrow, 0x4000000) == 0 or bit.band(bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)), 0x40) == 0) then
					local theinternalFlags = bit.bor(IEex_ReadDword(eData + 0xD0), IEex_ReadDword(eData + 0xD8))
					local thecasterlvl = IEex_ReadDword(eData + 0xC8)
					if thecasterlvl <= 0 then
						thecasterlvl = 1
					end
					local newEffectTarget = targetID
					local newEffectTargetX = IEex_ReadDword(effectData + 0x84)
					local newEffectTargetY = IEex_ReadDword(effectData + 0x88)
					if (bit.band(thesavingthrow, 0x200000) > 0) then
						newEffectTarget = sourceID
						newEffectTargetX = IEex_ReadDword(effectData + 0x7C)
						newEffectTargetY = IEex_ReadDword(effectData + 0x80)
					end
					local newEffectSource = thesourceID
					local newEffectSourceX = IEex_ReadDword(effectData + 0x7C)
					local newEffectSourceY = IEex_ReadDword(effectData + 0x80)
					if not IEex_IsSprite(thesourceID, false) then
						newEffectSource = sourceID
					end
					if (bit.band(thesavingthrow, 0x80000) > 0) then
						newEffectSource = sourceID
					elseif (bit.band(thesavingthrow, 0x400000) > 0) then
						newEffectSource = targetID
						newEffectSourceX = IEex_ReadDword(effectData + 0x84)
						newEffectSourceY = IEex_ReadDword(effectData + 0x88)
					end
					local usesLeft = IEex_ReadWord(eData + 0x4A, 0x0)
					if usesLeft == 1 then
						local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
						table.insert(sourceExpired, theparent_resource)
					elseif usesLeft > 0 then
						usesLeft = usesLeft - 1
						IEex_WriteWord(eData + 0x4A, usesLeft)
					end
					table.insert(onHitEffectList, {spellRES, thecasterlvl, newEffectTarget, newEffectSource, newEffectTargetX, newEffectTargetY, newEffectSourceX, newEffectSourceY, theinternalFlags})
				end
			end
		end)
--	end
	for k, v in ipairs(onHitEffectList) do
		IEex_ApplyEffectToActor(v[3], {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = v[1],
["source_x"] = v[7],
["source_y"] = v[8],
["target_x"] = v[5],
["target_y"] = v[6],
["casterlvl"] = v[2],
["internal_flags"] = v[9],
["parent_resource"] = v[1],
["source_target"] = v[3],
["source_id"] = v[4]
})
	end
	for k, v in ipairs(sourceExpired) do
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = v,
["source_id"] = sourceID
})
	end
	local targetExpired = {}
	local onBeingHitEffectList = {}
--	if IEex_GetActorSpellState(targetID, 225) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 225 and bit.band(thesavingthrow, 0x100000) > 0 and bit.band(thesavingthrow, 0x800000) == 0 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local matchHeader = IEex_ReadWord(eData + 0x48, 0x0)
				local spellRES = IEex_ReadLString(eData + 0x30, 8)
				local thesourceid = IEex_ReadDword(eData + 0x110)
				if theparameter1 == index and spellRES ~= "" and (matchHeader == 0 or matchHeader == headerType) then
					local theinternalFlags = bit.bor(IEex_ReadDword(eData + 0xD0), IEex_ReadDword(eData + 0xD8))
					local thecasterlvl = IEex_ReadDword(eData + 0xC8)
					if thecasterlvl <= 0 then
						thecasterlvl = 1
					end
					local newEffectTarget = targetID
					local newEffectTargetX = IEex_ReadDword(effectData + 0x84)
					local newEffectTargetY = IEex_ReadDword(effectData + 0x88)
					if (bit.band(thesavingthrow, 0x200000) > 0) then
						newEffectTarget = sourceID
						newEffectTargetX = IEex_ReadDword(effectData + 0x7C)
						newEffectTargetY = IEex_ReadDword(effectData + 0x80)
					end
					local newEffectSource = thesourceID
					local newEffectSourceX = IEex_ReadDword(effectData + 0x7C)
					local newEffectSourceY = IEex_ReadDword(effectData + 0x80)
					if not IEex_IsSprite(thesourceID, false) then
						newEffectSource = sourceID
					end
					if (bit.band(thesavingthrow, 0x80000) > 0) then
						newEffectSource = sourceID
					elseif (bit.band(thesavingthrow, 0x400000) > 0) then
						newEffectSource = targetID
						newEffectSourceX = IEex_ReadDword(effectData + 0x84)
						newEffectSourceY = IEex_ReadDword(effectData + 0x88)
					end
					local usesLeft = IEex_ReadWord(eData + 0x4A, 0x0)
					if usesLeft == 1 then
						local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
						table.insert(targetExpired, theparent_resource)
					elseif usesLeft > 0 then
						usesLeft = usesLeft - 1
						IEex_WriteWord(eData + 0x4A, usesLeft)
					end
					table.insert(onBeingHitEffectList, {spellRES, thecasterlvl, newEffectTarget, newEffectSource, newEffectTargetX, newEffectTargetY, newEffectSourceX, newEffectSourceY, theinternalFlags})
				end
			end
		end)
--	end
	for k, v in ipairs(onBeingHitEffectList) do
		IEex_ApplyEffectToActor(v[3], {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = v[1],
["source_x"] = v[7],
["source_y"] = v[8],
["target_x"] = v[5],
["target_y"] = v[6],
["casterlvl"] = v[2],
["internal_flags"] = v[9],
["parent_resource"] = v[1],
["source_target"] = v[3],
["source_id"] = v[4]
})
	end
	for k, v in ipairs(targetExpired) do
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = v,
["source_id"] = targetID
})
	end
end

function MEEXHIT(effectData, creatureData)
	MEONHIT(effectData, creatureData)
--[[
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local index = IEex_ReadDword(effectData + 0x1C)
	local headerType = IEex_ReadDword(effectData + 0x44)
	local sourceExpired = {}
	if IEex_GetActorSpellState(sourceID, 225) then
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 225 and bit.band(thesavingthrow, 0x100000) == 0 and bit.band(thesavingthrow, 0x800000) == 0 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local matchHeader = IEex_ReadWord(eData + 0x48, 0x0)
				local spellRES = IEex_ReadLString(eData + 0x30, 8)
				if theparameter1 == index and spellRES ~= "" and (matchHeader == 0 or matchHeader == headerType) and (bit.band(thesavingthrow, 0x4000000) == 0 or bit.band(bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)), 0x40) == 0) then
					local thecasterlvl = IEex_ReadDword(eData + 0xC8)
					local newEffectTarget = targetID
					local newEffectTargetX = IEex_ReadDword(effectData + 0x84)
					local newEffectTargetY = IEex_ReadDword(effectData + 0x88)
					if (bit.band(thesavingthrow, 0x200000) > 0) then
						newEffectTarget = sourceID
						newEffectTargetX = IEex_ReadDword(effectData + 0x7C)
						newEffectTargetY = IEex_ReadDword(effectData + 0x80)
					end
					local newEffectSource = sourceID
					local newEffectSourceX = IEex_ReadDword(effectData + 0x7C)
					local newEffectSourceY = IEex_ReadDword(effectData + 0x80)
					if (bit.band(thesavingthrow, 0x400000) > 0) then
						newEffectSource = targetID
						newEffectSourceX = IEex_ReadDword(effectData + 0x84)
						newEffectSourceY = IEex_ReadDword(effectData + 0x88)
					end
					local usesLeft = IEex_ReadWord(eData + 0x4A, 0x0)
					if usesLeft == 1 then
						local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
						table.insert(sourceExpired, theparent_resource)
					elseif usesLeft > 0 then
						usesLeft = usesLeft - 1
						IEex_WriteWord(eData + 0x4A, usesLeft)
					end
					IEex_ApplyEffectToActor(newEffectTarget, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["source_x"] = newEffectSourceX,
["source_y"] = newEffectSourceY,
["target_x"] = newEffectTargetX,
["target_y"] = newEffectTargetY,
["casterlvl"] = thecasterlvl,
["parent_resource"] = spellRES,
["source_target"] = newEffectTarget,
["source_id"] = newEffectSource
})
				end
			end
		end)
	end
	for k, v in ipairs(sourceExpired) do
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = v,
["source_id"] = sourceID
})
	end
	local targetExpired = {}
	if IEex_GetActorSpellState(targetID, 225) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 225 and bit.band(thesavingthrow, 0x100000) > 0 and bit.band(thesavingthrow, 0x800000) == 0 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local matchHeader = IEex_ReadWord(eData + 0x48, 0x0)
				local spellRES = IEex_ReadLString(eData + 0x30, 8)
				if theparameter1 == index and spellRES ~= "" and (matchHeader == 0 or matchHeader == headerType) then
					local thecasterlvl = IEex_ReadDword(eData + 0xC8)
					local newEffectTarget = targetID
					local newEffectTargetX = IEex_ReadDword(effectData + 0x84)
					local newEffectTargetY = IEex_ReadDword(effectData + 0x88)
					if (bit.band(thesavingthrow, 0x200000) > 0) then
						newEffectTarget = sourceID
						newEffectTargetX = IEex_ReadDword(effectData + 0x7C)
						newEffectTargetY = IEex_ReadDword(effectData + 0x80)
					end
					local newEffectSource = sourceID
					local newEffectSourceX = IEex_ReadDword(effectData + 0x7C)
					local newEffectSourceY = IEex_ReadDword(effectData + 0x80)
					if (bit.band(thesavingthrow, 0x400000) > 0) then
						newEffectSource = targetID
						newEffectSourceX = IEex_ReadDword(effectData + 0x84)
						newEffectSourceY = IEex_ReadDword(effectData + 0x88)
					end
					local usesLeft = IEex_ReadWord(eData + 0x4A, 0x0)
					if usesLeft == 1 then
						local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
						table.insert(targetExpired, theparent_resource)
					elseif usesLeft > 0 then
						usesLeft = usesLeft - 1
						IEex_WriteWord(eData + 0x4A, usesLeft)
					end
					IEex_ApplyEffectToActor(newEffectTarget, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["source_x"] = newEffectSourceX,
["source_y"] = newEffectSourceY,
["target_x"] = newEffectTargetX,
["target_y"] = newEffectTargetY,
["casterlvl"] = thecasterlvl,
["parent_resource"] = spellRES,
["source_target"] = newEffectTarget,
["source_id"] = newEffectSource
})
				end
			end
		end)
	end
	for k, v in ipairs(targetExpired) do
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = v,
["source_id"] = targetID
})
	end
--]]
end

function MEONSONG(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local songType = IEex_ReadDword(effectData + 0x44)
	local onSongEffectList = {}
	if IEex_GetActorSpellState(sourceID, 229) then
		local cea = IEex_CompareActorAllegiances(sourceID, targetID)
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 229 then
				local matchSongType = IEex_ReadDword(eData + 0x48)
				local spellRES = IEex_ReadLString(eData + 0x30, 8)
				if spellRES ~= "" and (matchSongType == -1 or matchSongType == matchSongType) and (bit.band(thesavingthrow, 0x2000000) == 0 or cea ~= 1) and (bit.band(thesavingthrow, 0x4000000) == 0 or cea ~= 0) and (bit.band(thesavingthrow, 0x8000000) == 0 or cea ~= -1) and (bit.band(thesavingthrow, 0x10000000) == 0 or sourceID ~= targetID) then
					local thecasterlvl = IEex_ReadDword(eData + 0xC8)
					local newEffectTarget = targetID
					local newEffectTargetX = IEex_ReadDword(effectData + 0x84)
					local newEffectTargetY = IEex_ReadDword(effectData + 0x88)
					if (bit.band(thesavingthrow, 0x200000) > 0) then
						newEffectTarget = sourceID
						newEffectTargetX = IEex_ReadDword(effectData + 0x7C)
						newEffectTargetY = IEex_ReadDword(effectData + 0x80)
					end
					local newEffectSource = sourceID
					local newEffectSourceX = IEex_ReadDword(effectData + 0x7C)
					local newEffectSourceY = IEex_ReadDword(effectData + 0x80)
					if (bit.band(thesavingthrow, 0x400000) > 0) then
						newEffectSource = targetID
						newEffectSourceX = IEex_ReadDword(effectData + 0x84)
						newEffectSourceY = IEex_ReadDword(effectData + 0x88)
					end
					table.insert(onSongEffectList, {spellRES, thecasterlvl, newEffectTarget, newEffectSource, newEffectTargetX, newEffectTargetY, newEffectSourceX, newEffectSourceY})
				end
			end
		end)
	end
	for k, v in ipairs(onSongEffectList) do
		IEex_ApplyEffectToActor(v[3], {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = v[1],
["source_x"] = v[7],
["source_y"] = v[8],
["target_x"] = v[5],
["target_y"] = v[6],
["casterlvl"] = v[2],
["parent_resource"] = v[1],
["source_target"] = v[3],
["source_id"] = v[4]
})
	end
end

repeat_record = {}
--[[
function IEex_CheckForEffectRepeat(actorID, effectData)
	if bit.band(IEex_ReadDword(effectData + 0x3C), 0x4000) > 0 then return false end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local special = IEex_ReadDword(effectData + 0x44)
	local time = IEex_ReadDword(effectData + 0x24)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local funcName = IEex_ReadLString(effectData + 0x2C, 8)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	if repeat_record[actorID] == nil then
		repeat_record[actorID] = {}
	end
	local newTick = false
	if repeat_record[actorID][funcName] == nil then
		repeat_record[actorID][funcName] = {}
	else
		for k, v in ipairs(repeat_record[actorID][funcName]) do
			if v["time"] ~= time then
				newTick = true
			elseif v["parameter1"] == parameter1 and v["parameter2"] == parameter2 and v["special"] == special and v["sourceID"] == sourceID and v["parent_resource"] == parent_resource then
				return true
			end
		end
	end
	if newTick then
		repeat_record[actorID][funcName] = {}
	end
	table.insert(repeat_record[actorID][funcName], {["parameter1"] = parameter1, ["parameter2"] = parameter2, ["special"] = special, ["time"] = time, ["sourceID"] = sourceID, ["parent_resource"] = parent_resource})
	return false
end
--]]
function IEex_CheckForEffectRepeat(effectData, creatureData)
	local actorID = IEex_GetActorIDShare(creatureData)
--	if bit.band(IEex_ReadDword(effectData + 0x3C), 0x4000) > 0 then return false end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local special = IEex_ReadDword(effectData + 0x44)
	local time = IEex_ReadDword(effectData + 0x24)
	local randomIdentifier = IEex_ReadDword(effectData + 0xD0)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local funcName = IEex_ReadLString(effectData + 0x2C, 8)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	if repeat_record[actorID] == nil then
		repeat_record[actorID] = {}
	end
	local newTick = false
	if repeat_record[actorID][funcName] == nil then
		repeat_record[actorID][funcName] = {}
	else
		for k, v in ipairs(repeat_record[actorID][funcName]) do
			if v["time"] ~= time then
				newTick = true
			elseif v["effectData"] == effectData and v["randomIdentifier"] == randomIdentifier then
				return true
			end
		end
	end
	if newTick then
		repeat_record[actorID][funcName] = {}
	end
	table.insert(repeat_record[actorID][funcName], {["effectData"] = effectData, ["time"] = time, ["randomIdentifier"] = randomIdentifier,})
	return false
end
loop_record = {}

function IEex_CheckForInfiniteLoop(actorID, time, funcName, repeatLimit)
	if loop_record[actorID] == nil then
		loop_record[actorID] = {}
	end
	if loop_record[actorID][funcName] ~= nil and time == loop_record[actorID][funcName][1] then
		loop_record[actorID][funcName][1] = time
		local repeatCount = loop_record[actorID][funcName][2]
		repeatCount = repeatCount + 1
--		print("" .. repeatCount)
		if repeatCount >= repeatLimit then
			return true
		else
			loop_record[actorID][funcName][2] = repeatCount
		end
	else
		loop_record[actorID][funcName] = {time, 1}
	end
	return false
end

function MEREPERM(effectData, creatureData)
	if true then return end
end
ex_last_evaluation_tick = {}
ex_record_projectile_position = {}
ex_record_temporal_position = {}

ex_current_read_offset = 0
ex_burst_tick = 0
ex_current_angle = {}
ex_current_angle_index = {}
ex_projectile_redirect = {}
ex_party_cast_counter = {}
ex_done_reading = false
ex_barrage_angle_pattern = {
[0] = {0},
[1] = {1},
[2] = {2},
[3] = {3},
[4] = {4},
[5] = {5},
[6] = {6},
[7] = {7},
[8] = {8},
[9] = {9},
[10] = {10},
[11] = {11},
[12] = {12},
[13] = {13},
[14] = {14},
[15] = {15},
[16] = {16},
[17] = {17},
[18] = {18},
[19] = {19},
[20] = {20},
[30] = {30},
[40] = {40},
[45] = {45},
[50] = {50},
[60] = {60},
[70] = {70},
[80] = {80},
[90] = {90},
[135] = {135},
[180] = {180},
[225] = {225},
[270] = {270},
[315] = {315},
[360] = {360},
[2956] = {33, 33, 33, 27},
}
ex_spell_pattern_index = {
["USWI956D"] = 2956,
}
ex_hex_to_decimal = {["0"] = 0, ["1"] = 1, ["2"] = 2, ["3"] = 3, ["4"] = 4, ["5"] = 5, ["6"] = 6, ["7"] = 7, ["8"] = 8, ["9"] = 9, ["A"] = 10, ["B"] = 11, ["C"] = 12, ["D"] = 13, ["E"] = 14, ["F"] = 15, }
function IEex_EvaluatePermanentRepeatingEffects(creatureData)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
--	if IEex_ReadDword(effectData + 0x10C) <= 0 then return end
	local usedFunction = false
	local tick = IEex_GetGameTick()
	local targetID = IEex_GetActorIDShare(creatureData)
--[[
	if tick % 15 == 0 and targetID == IEex_GetActorIDCharacter(0) then
		IEex_Search(107, creatureData, 0x8000, false)
	end
--]]
--	if IEex_CheckForInfiniteLoop(targetID, IEex_ReadDword(effectData + 0x24), "MEREPERM", 5) then return end
	if IEex_ReadSignedByte(creatureData + 0x603, 0x0) == -1 and IEex_IsPartyMember(targetID) then
		IEex_WriteByte(creatureData + 0x603, 0)
	end
	IEex_WriteWord(creatureData + 0x708, IEex_ReadSignedWord(creatureData + 0x5C0, 0x0))

	local castCounter = IEex_ReadSignedByte(creatureData + 0x54E8, 0x0)
	if castCounter > -1 and ex_really_force_spell_opcode_tick[targetID] ~= nil then
		local actionID = IEex_ReadWord(creatureData + 0x476, 0x0)
		if tick - ex_really_force_spell_opcode_tick[targetID] <= 2 and (actionID == 191 or actionID == 192) then
			IEex_WriteByte(creatureData + 0x54E8, 126)
		end
	end
	local baseCriticalHitImmunity = IEex_ReadSignedByte(creatureData + 0x70A, 0x0)
	if baseCriticalHitImmunity == -1 then
		if bit.band(IEex_ReadByte(creatureData + 0x89F, 0x0), 0x2) > 0 then
			baseCriticalHitImmunity = 1
		else
			baseCriticalHitImmunity = 0
		end
		IEex_WriteByte(creatureData + 0x70A, baseCriticalHitImmunity)
	end
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	local joinedParty = (bit.band(extraFlags, 0x100) > 0)
	if IEex_IsPartyMember(targetID) then
		for i = 0, 5, 1 do
			local currentID = IEex_GetActorIDPortrait(i)
			if currentID == targetID then
				ex_party_cast_counter[i + 1] = castCounter
			end
		end
		if not joinedParty then
			extraFlags = bit.bor(extraFlags, 0x100)
			IEex_WriteDword(creatureData + 0x740, extraFlags)
			local attributes = IEex_ReadByte(creatureData + 0x89F, 0x0)
			attributes = bit.band(attributes, 0xFE)
			IEex_WriteByte(creatureData + 0x89F, attributes)
			local scriptName = IEex_ReadLString(creatureData + 0x554, 32)
			local onJoinPartyDLG = ex_on_join_party_dlg_set[scriptName]
			if onJoinPartyDLG == nil then
				onJoinPartyDLG = ex_on_join_party_dlg_set["DEFAULT"]
			end
			IEex_WriteLString(creatureData + 0x56DC, onJoinPartyDLG, 8)
			local onJoinPartyTeamScript = ex_on_join_party_team_script_set[scriptName]
			if onJoinPartyTeamScript ~= nil then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 82,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 2,
["resource"] = onJoinPartyTeamScript,
["source_id"] = targetID,
})
--				IEex_WriteLString(creatureData + 0x748, onJoinPartyTeamScript, 8)
			end
			local onJoinPartySpecialScript1 = ex_on_join_party_special_script_1_set[scriptName]
			if onJoinPartySpecialScript1 ~= nil then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 82,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 1,
["resource"] = onJoinPartySpecialScript1,
["source_id"] = targetID,
})
--				IEex_WriteLString(creatureData + 0x750, onJoinPartySpecialScript1, 8)
			end
		end
		if ex_disable_party_hof_bonus_bug then
			local allegiance = IEex_ReadByte(creatureData + 0x24, 0x0)
			if allegiance ~= 2 then
				local attributes = IEex_ReadByte(creatureData + 0x89F, 0x0)
				attributes = bit.bor(attributes, 0x1)
				IEex_WriteByte(creatureData + 0x89F, attributes)
			else
				local attributes = IEex_ReadByte(creatureData + 0x89F, 0x0)
				attributes = bit.band(attributes, 0xFE)
				IEex_WriteByte(creatureData + 0x89F, attributes)
			end
		end
		local timeOfDeath = IEex_ReadDword(creatureData + 0x704)
		if not IEex_GetActorState(targetID, 0xFC0) and timeOfDeath ~= -1 then
			IEex_WriteDword(creatureData + 0x704, -1)
		elseif IEex_GetActorState(targetID, 0xFC0) and timeOfDeath == -1 then
			if timeOfDeath == -1 then
				IEex_WriteDword(creatureData + 0x704, tick)
			end
		else
			for i = 0, 5, 1 do
				local currentID = IEex_GetActorIDPortrait(i)
				if currentID > 0 then
					local currentShare = IEex_GetActorShare(currentID)
					local currentTimeOfDeath = IEex_ReadDword(currentShare + 0x704)
					if IEex_GetActorState(currentID, 0xFC0) and currentTimeOfDeath ~= -1 and tick - currentTimeOfDeath >= 36000 and IEex_GetActorSpellState(currentID, 206) then
						IEex_WriteDword(currentShare + 0x704, -1)
						IEex_ApplyEffectToActor(currentID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["savingthrow"] = 0x20000,
["resource"] = "MERAISED",
["source_id"] = currentID
})
						IEex_ApplyEffectToActor(currentID, {
["opcode"] = 17,
["target"] = 2,
["parameter1"] = 100,
["parameter2"] = 2,
["timing"] = 1,
["source_id"] = currentID
})
						IEex_ApplyEffectToActor(currentID, {
["opcode"] = 233,
["target"] = 2,
["parameter2"] = 15,
["timing"] = 9,
["source_id"] = currentID
})
					end
				end
			end
		end
	else
		if joinedParty then
			extraFlags = bit.band(extraFlags, 0xFFFFFEFF)
			IEex_WriteDword(creatureData + 0x740, extraFlags)
			local attributes = IEex_ReadByte(creatureData + 0x89F, 0x0)
			attributes = bit.bor(attributes, 0x1)
			IEex_WriteByte(creatureData + 0x89F, attributes)
			local scriptName = IEex_ReadLString(creatureData + 0x554, 32)
			local onLeavePartyDLG = ex_on_leave_party_dlg_set[scriptName]
			if onLeavePartyDLG == nil then
				onLeavePartyDLG = ex_on_leave_party_dlg_set["DEFAULT"]
			end
			IEex_WriteLString(creatureData + 0x56DC, onLeavePartyDLG, 8)
			local onLeavePartyTeamScript = ex_on_leave_party_team_script_set[scriptName]
			if onLeavePartyTeamScript ~= nil then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 82,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 2,
["resource"] = onLeavePartyTeamScript,
["source_id"] = targetID,
})
--				IEex_WriteLString(creatureData + 0x748, onJoinPartyTeamScript, 8)
			end
		end
	end
	local sourceAnimationData = IEex_ReadDword(creatureData + 0x50F0)
	if sourceAnimationData > 0 then
		local sourcePersonalSpace = IEex_ReadByte(sourceAnimationData + 0x3E4, 0x0)
		if sourcePersonalSpace == 1 then
			local actionTargetID = IEex_ReadDword(creatureData + 0x4BE)
			if IEex_IsSprite(actionTargetID, false) then
				local targetPersonalSpace = IEex_ReadByte(IEex_ReadDword(IEex_GetActorShare(actionTargetID) + 0x50F0) + 0x3E4, 0x0)
				if targetPersonalSpace ~= 1 then
					IEex_WriteByte(sourceAnimationData + 0x3E4, 3)
				end
			else
				IEex_WriteByte(sourceAnimationData + 0x3E4, 3)
			end
		end
	end
	if (IEex_ReadByte(creatureData + 0x4C53, 0x0) == 2 or (IEex_ReadByte(creatureData + 0x26, 0x0) == 2 and ex_elf_automatic_search)) and IEex_ReadByte(creatureData + 0x24, 0x0) <= 30 and tick % ex_detect_traps_period == 0 then
		local searchSkill = IEex_GetActorStat(targetID, 28)
		local searchRadius = ex_detect_traps_radius + searchSkill * ex_detect_traps_radius_increase_per_search_skill_point
		if searchRadius > 400 then
			searchRadius = 400
		end
		local targetX, targetY = IEex_GetActorLocation(targetID)
		local areaData = IEex_ReadDword(creatureData + 0x12)
		local autoPause = false
		IEex_IterateIDs(areaData, 0x11, function(id)
			local share = IEex_GetActorShare(id)
			if IEex_ReadWord(share + 0x896, 0x0) > 0 and IEex_ReadLString(share + 0x864, 8) ~= "" then
				local trapX = math.floor((IEex_ReadDword(share + 0x598) + IEex_ReadDword(share + 0x5A0)) / 2)
				local trapY = math.floor((IEex_ReadDword(share + 0x59C) + IEex_ReadDword(share + 0x5A4)) / 2)
				local trapDetectDifficulty = IEex_ReadSignedWord(share + 0x892, 0x0)
				if trapDetectDifficulty >= 1000 then
					trapDetectDifficulty = trapDetectDifficulty - 1000
				end
				if trapDetectDifficulty ~= 100 and searchSkill + 4 >= math.floor(trapDetectDifficulty / 5) and IEex_GetDistanceIsometric(targetX, targetY, trapX, trapY) <= searchRadius then
					if IEex_ReadWord(share + 0x898, 0x0) == 0 then
						autoPause = true
						IEex_WriteWord(share + 0x898, 1)
					end
					IEex_WriteWord(share + 0x8D0, 313)
				end
			end
		end)
		IEex_IterateIDs(areaData, 0x21, function(id)
			local share = IEex_GetActorShare(id)
			local doorFlags = IEex_ReadDword(share + 0x5C4)
			if IEex_ReadWord(share + 0x64C, 0x0) > 0 and bit.band(doorFlags, 0x8) > 0 and (bit.band(doorFlags, 0x80) == 0 or bit.band(doorFlags, 0x100) > 0) and IEex_ReadLString(share + 0x5F0, 8) ~= "" then
				local trapX = math.floor((IEex_ReadDword(share + 0x5B0) + IEex_ReadDword(share + 0x5B8)) / 2)
				local trapY = math.floor((IEex_ReadDword(share + 0x5B4) + IEex_ReadDword(share + 0x5BC)) / 2)
				local trapDetectDifficulty = IEex_ReadSignedWord(share + 0x648, 0x0)
				if trapDetectDifficulty >= 1000 then
					trapDetectDifficulty = trapDetectDifficulty - 1000
				end
				if trapDetectDifficulty ~= 100 and searchSkill + 4 >= math.floor(trapDetectDifficulty / 5) and IEex_GetDistanceIsometric(targetX, targetY, trapX, trapY) <= searchRadius then
					if IEex_ReadWord(share + 0x64E, 0x0) == 0 then
						autoPause = true
						IEex_WriteWord(share + 0x64E, 1)
					end
					IEex_WriteWord(share + 0x664, 313)
				end
			end
		end)
		IEex_IterateIDs(areaData, 0x41, function(id)
			local share = IEex_GetActorShare(id)
			local triggerFlags = IEex_ReadDword(share + 0x5D6)
			if IEex_ReadWord(share + 0x612, 0x0) > 0 and bit.band(triggerFlags, 0x8) > 0 and bit.band(triggerFlags, 0x100) == 0 and IEex_ReadLString(share + 0x5E6, 8) ~= "" then
				local trapX = math.floor((IEex_ReadDword(share + 0x59A) + IEex_ReadDword(share + 0x5A2)) / 2)
				local trapY = math.floor((IEex_ReadDword(share + 0x59E) + IEex_ReadDword(share + 0x5A6)) / 2)
				local trapDetectDifficulty = IEex_ReadSignedWord(share + 0x60E, 0x0)
				if trapDetectDifficulty >= 1000 then
					trapDetectDifficulty = trapDetectDifficulty - 1000
				end
				if trapDetectDifficulty ~= 100 and searchSkill + 4 >= math.floor(trapDetectDifficulty / 5) and IEex_GetDistanceIsometric(targetX, targetY, trapX, trapY) <= searchRadius then
					if IEex_ReadWord(share + 0x614, 0x0) == 0 then
						autoPause = true
						IEex_WriteWord(share + 0x614, 1)
					end
					IEex_WriteWord(share + 0x626, 313)
				end
			end
		end)
		if autoPause then
			IEex_Call(IEex_ReadDword(IEex_ReadDword(creatureData) + 0xB0), {0x80}, creatureData, 0x0)
		end
	end
	if targetID == IEex_GetActorIDCharacter(0) then
--[[
		IEex_IterateProjectiles(targetID, -1, function(projectileData)
			key_angles = {-90, -67.5, -45, -22.5, 0, 22.5, 45, 67.5, 90}
			local projectileX = IEex_ReadDword(projectileData + 0x6)
			local projectileY = IEex_ReadDword(projectileData + 0xA)
			local projectileFlags = IEex_ReadWord(projectileData + 0x1C, 0x0)
			local missile = IEex_ReadWord(projectileData + 0x6E, 0x0) + 1
--			if (missile == 40 or (missile == 1 and IEex_ReadLString(projectileData + 0xFA, 8) == "TRA_09B")) and tick % 5 == 0 and bit.band(projectileFlags, 0x1000) == 0 then
			if (missile == 40 or (missile == 1 and IEex_ReadLString(projectileData + 0xFA, 8) == "TRA_09B")) and tick - ex_burst_tick >= 5 and bit.band(projectileFlags, 0x1000) > 0 and bit.band(projectileFlags, 0x2000) == 0 then
--				projectileFlags = bit.bor(projectileFlags, 0x1000)
				projectileFlags = bit.bor(projectileFlags, 0x2000)
				IEex_WriteWord(projectileData + 0x1C, projectileFlags)
				local sourceID = IEex_ReadDword(projectileData + 0x72)
				if ex_projectile_redirect[sourceID] ~= nil and IEex_IsSprite(ex_projectile_redirect[sourceID], true) then
					local redirectID = ex_projectile_redirect[sourceID]
					local redirectX, redirectY = IEex_GetActorLocation(redirectID)
					local speed = IEex_ReadSignedWord(projectileData + 0x70, 0x0)
					local speedX = IEex_ReadDword(projectileData + 0xA4) / speed
					local speedY = IEex_ReadDword(projectileData + 0xA8) * .75 / speed
					local speedH = (speedX ^ 2 + speedY ^ 2) ^ .5
					local newDeltaX = redirectX - projectileX
					local newDeltaY = redirectY - projectileY
					local newDeltaH = (newDeltaX ^ 2 + newDeltaY ^ 2) ^ .5
					if newDeltaH ~= 0 then
						local newSpeedX = math.floor(newDeltaX / newDeltaH * speedH * speed)
						local newSpeedY = math.floor(newDeltaY / newDeltaH * speedH * speed * 4 / 3)
						IEex_WriteDword(projectileData + 0xA4, newSpeedX)
						IEex_WriteDword(projectileData + 0xA8, newSpeedY)
						if newDeltaX ~= 0 then
							local angle = math.deg(math.atan(newDeltaY / newDeltaX))
							local angleRounded = false
							for i = 1, 9, 1 do
								if angleRounded == false and ((angle >= key_angles[i] and angle - 11.25 <= key_angles[i]) or (angle <= key_angles[i] and angle + 11.25 >= key_angles[i])) then
									angleRounded = true
									angle = key_angles[i]
									IEex_WriteWord(projectileData + 0x1DC, i - 1)
								end
							end
						else
							if newDeltaY > 0 then
								IEex_WriteWord(projectileData + 0x1DC, 0)
							else
								IEex_WriteWord(projectileData + 0x1DC, 8)
							end
						end
					end	
					IEex_WriteDword(projectileData + 0x76, -1)
	--				IEex_WriteDword(projectileData + 0xC8, targetX + newDeltaX * 100)
	--				IEex_WriteDword(projectileData + 0xCC, targetY + newDeltaY * 100)
				end
			end
		end)
--]]
		IEex_IterateProjectiles(targetID, -1, function(projectileData)
			key_angles = {-90, -67.5, -45, -22.5, 0, 22.5, 45, 67.5, 90}
			local projectileX = IEex_ReadDword(projectileData + 0x6)
			local projectileY = IEex_ReadDword(projectileData + 0xA)
			local projectileFlags = IEex_ReadWord(projectileData + 0x1C, 0x0)
			local missile = IEex_ReadWord(projectileData + 0x6E, 0x0) + 1
			local sourceID = IEex_ReadDword(projectileData + 0x72)
			local spellRES = IEex_Helper_GetBridge("IEex_RecordOpcode430Spell", sourceID, "spellRES")

			if missile == 1 and IEex_ReadLString(projectileData + 0xFA, 8) == "TRA_09B" then
				local timeRemaining = IEex_ReadByte(projectileData + 0x2AE, 0x0)
				IEex_WriteByte(projectileData + 0x2AE, timeRemaining + 1)
--				IEex_WriteByte(projectileData + 0x2B2, 120)
			end

			if (missile == 40 or (missile == 1 and IEex_ReadLString(projectileData + 0xFA, 8) == "TRA_09B")) and bit.band(projectileFlags, 0x1000) == 0 and spellRES ~= nil and ex_spell_pattern_index[spellRES] ~= nil then
				local pattern = ex_barrage_angle_pattern[ex_spell_pattern_index[spellRES]]
				ex_burst_tick = tick
				projectileFlags = bit.bor(projectileFlags, 0x1000)
				local sourceX, sourceY = IEex_GetActorLocation(sourceID)
				IEex_WriteWord(projectileData + 0x1C, projectileFlags)
				local speed = IEex_ReadSignedWord(projectileData + 0x70, 0x0)
				local speedX = IEex_ReadDword(projectileData + 0xA4) / speed
				local speedY = IEex_ReadDword(projectileData + 0xA8) * .75 / speed
				local speedH = (speedX ^ 2 + speedY ^ 2) ^ .5
				if ex_current_angle[sourceID] == nil then
					ex_current_angle[sourceID] = {[spellRES] = 0, }
				elseif ex_current_angle[sourceID][spellRES] == nil then
					ex_current_angle[sourceID][spellRES] = 0
				end
				if ex_current_angle_index[sourceID] == nil then
					ex_current_angle_index[sourceID] = {[spellRES] = 1, }
				elseif ex_current_angle_index[sourceID][spellRES] == nil then
					ex_current_angle_index[sourceID][spellRES] = 1
				end
				local delta = 100
				local newDeltaX = math.floor(math.cos(ex_current_angle[sourceID][spellRES]) * delta)
				local newDeltaY = math.floor(math.sin(ex_current_angle[sourceID][spellRES]) * delta)
				ex_current_angle[sourceID][spellRES] = ex_current_angle[sourceID][spellRES] + pattern[ex_current_angle_index[sourceID][spellRES]]
				ex_current_angle_index[sourceID][spellRES] = ex_current_angle_index[sourceID][spellRES] + 1
				if ex_current_angle_index[sourceID][spellRES] > #pattern then
					ex_current_angle_index[sourceID][spellRES] = 1
				end
				local newDeltaH = (newDeltaX ^ 2 + newDeltaY ^ 2) ^ .5
				if newDeltaH ~= 0 then
					local newSpeedX = math.floor(newDeltaX / newDeltaH * speedH * speed)
					local newSpeedY = math.floor(newDeltaY / newDeltaH * speedH * speed * 4 / 3)
					IEex_WriteDword(projectileData + 0xA4, newSpeedX)
					IEex_WriteDword(projectileData + 0xA8, newSpeedY)
					if newDeltaX ~= 0 then
						local angle = math.deg(math.atan(newDeltaY / newDeltaX))
						local angleRounded = false
						for i = 1, 9, 1 do
							if angleRounded == false and ((angle >= key_angles[i] and angle - 11.25 <= key_angles[i]) or (angle <= key_angles[i] and angle + 11.25 >= key_angles[i])) then
								angleRounded = true
								angle = key_angles[i]
								IEex_WriteWord(projectileData + 0x1DC, i - 1)
							end
						end
					else
						if newDeltaY > 0 then
							IEex_WriteWord(projectileData + 0x1DC, 0)
						else
							IEex_WriteWord(projectileData + 0x1DC, 8)
						end
					end
				end	
				IEex_WriteDword(projectileData + 0x76, -1)
				IEex_WriteDword(projectileData + 0xC8, sourceX + newDeltaX * 100)
				IEex_WriteDword(projectileData + 0xCC, sourceY + newDeltaY * 100)
			end
		end)

		IEex_IterateProjectiles(targetID, 108, function(share)
			local scorcherAnimationIndex = ex_custom_scorcher["DEFAULT"]["Index"]
			local startingTime = ex_custom_scorcher["DEFAULT"]["StartingTime"]
			local spellRES = IEex_ReadLString(share + 0x18A, 8)
			if spellRES == "" then
				local projectileSourceID = IEex_ReadDword(share + 0x72)
				if IEex_Helper_GetBridge("IEex_RecordOpcode430Spell", projectileSourceID, "spellRES") ~= nil then
					spellRES = IEex_Helper_GetBridge("IEex_RecordOpcode430Spell", projectileSourceID, "spellRES")
				end
			end
			if ex_custom_scorcher[spellRES] ~= nil then
				scorcherAnimationIndex = ex_custom_scorcher[spellRES]["Index"]
				startingTime = ex_custom_scorcher[spellRES]["StartingTime"]
			end
			local timeRemaining = IEex_ReadByte(share + 0x2AE, 0x0)
			local timeElapsed = IEex_ReadByte(share + 0x2C6, 0x0)
			if startingTime > 0 and startingTime > timeElapsed then
				timeRemaining = timeRemaining - (startingTime - timeElapsed)
				if timeRemaining < 1 then
					timeRemaining = 1
				end
				timeElapsed = startingTime
				IEex_WriteByte(share + 0x2AE, timeRemaining)
				IEex_WriteByte(share + 0x2C6, timeElapsed)
			end
			local animationData = IEex_ReadDword(share + 0x192)
			local cycle = IEex_ReadWord(animationData + 0xC6, 0x0)
			if cycle < 9 then
				cycle = cycle + 9 * scorcherAnimationIndex
			end
			IEex_WriteWord(animationData + 0xC6, cycle)
		end)
--[[
		IEex_IterateProjectiles(targetID, 37, function(projectileData)
--			local projectileSourceData = IEex_GetActorShare(IEex_ReadDword(projectileData + 0x72))
--			if projectileSourceData > 0 then
--				IEex_WriteWord(projectileData + 0x70, 1)
--				local projectileSourceX = IEex_ReadDword(projectileSourceData + 0x6)
--				local projectileSourceY = IEex_ReadDword(projectileSourceData + 0xA)
--				IEex_WriteDword(projectileData + 0x6, projectileSourceX)
--				IEex_WriteDword(projectileData + 0xA, projectileSourceY)
--				IEex_WriteDword(projectileData + 0x9C, projectileSourceX * 1024)
--				IEex_WriteDword(projectileData + 0xA0, math.floor(projectileSourceY * 1024 * 4 / 3))
--				IEex_WriteDword(projectileData + 0x116, projectileSourceX)
--				IEex_WriteDword(projectileData + 0x11A, projectileSourceY)
				local projectileType = IEex_ProjectileType[IEex_ReadWord(projectileData + 0x6E, 0x0) + 1]
				local projectileHasExploded = false
				if projectileType == 6 then
					projectileHasExploded = (IEex_ReadByte(projectileData + 0x2B6, 0x0) > 0)
					local timeRemaining = IEex_ReadSignedWord(projectileData + 0x4C0, 0x0)
					if timeRemaining > 0 then
						IEex_WriteWord(projectileData + 0x4C0, timeRemaining + 1)
					end
				end
				if not projectileHasExploded then
					local projectileAnimationData = IEex_ReadDword(projectileData + 0x192)
					if projectileAnimationData > 65535 then
						local frame = IEex_ReadSignedWord(projectileAnimationData + 0xC4, 0x0)
						print(frame)
--						if frame > 0 then
							IEex_WriteWord(projectileAnimationData + 0xC4, 2)
--						end
					end
				end
				if ex_record_projectile_position[projectileData] == nil then
					ex_record_projectile_position[projectileData] = {IEex_ReadDword(projectileData + 0x6), IEex_ReadDword(projectileData + 0xA)}
				end
				local newX = ex_record_projectile_position[projectileData][1]
				local newY = ex_record_projectile_position[projectileData][2]
				IEex_WriteDword(projectileData + 0x6, newX)
				IEex_WriteDword(projectileData + 0xA, newY)
				IEex_WriteDword(projectileData + 0x9C, newX * 1024 - IEex_ReadDword(projectileData + 0xA4))
				IEex_WriteDword(projectileData + 0xA0, math.floor(newY * 1024 * 4 / 3) - IEex_ReadDword(projectileData + 0xA8))
--				IEex_WriteDword(projectileData + 0xA4, 0)
--				IEex_WriteDword(projectileData + 0xA8, 0)
				IEex_WriteDword(projectileData + 0x116, newX)
				IEex_WriteDword(projectileData + 0x11A, newY)
--			end
		end)
--]]
		local globalEffectFlags = IEex_GetGlobalEffectFlags()
		if bit.band(globalEffectFlags, 0xB) > 0 and IEex_InCutsceneMode() then
			IEex_SetGlobalEffectFlags(0xB, 0)
			globalEffectFlags = IEex_GetGlobalEffectFlags()
		end
--[[
		local globalEffectFlags = 0
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			if theopcode == 288 and theparameter2 == 230 and bit.band(thesavingthrow, 0x10000) == 0 and IEex_ReadDword(eData + 0x114) == 0 then
				local thespecial = IEex_ReadDword(eData + 0x48)
				if IEex_InCutsceneMode() and bit.band(thespecial, 0xB) > 0 then
					IEex_WriteDword(eData + 0x114, 1)
				else
					globalEffectFlags = bit.bor(globalEffectFlags, thespecial)
				end
			end
		end)
		IEex_WriteDword(creatureData + 0x73C, globalEffectFlags)
--]]
		if bit.band(globalEffectFlags, 0xA) > 0 then
			if tick % ex_time_slow_speed_divisor ~= 0 or bit.band(globalEffectFlags, 0x8) > 0 then
				IEex_IterateProjectiles(targetID, -1, function(projectileData)

					local missileIndex = IEex_ReadWord(projectileData + 0x6E, 0x0) + 1

					local projectileType = IEex_ProjectileType[missileIndex]
					local projectileHasExploded = false
					if missileIndex == 40 or missileIndex == 79 then
						local timeRemaining = IEex_ReadByte(projectileData + 0x29E, 0x0)
						IEex_WriteByte(projectileData + 0x29E, timeRemaining + 1)
--					elseif missileIndex == 1 and IEex_ReadLString(projectileData + 0xFA, 8) == "TRA_09B" then
--						local timeRemaining = IEex_ReadByte(projectileData + 0x2AE, 0x0)
--						IEex_WriteByte(projectileData + 0x2AE, timeRemaining + 1)
					end
					if projectileType == 6 then
						projectileHasExploded = (IEex_ReadByte(projectileData + 0x2B6, 0x0) > 0)
						local timeRemaining = IEex_ReadSignedWord(projectileData + 0x4C0, 0x0)
						if timeRemaining > 0 then
							IEex_WriteWord(projectileData + 0x4C0, timeRemaining + 1)
						end
					end


					if not projectileHasExploded then

						local projectileAnimationData = IEex_ReadDword(projectileData + 0x192)
						if projectileAnimationData >= 0x10000 and projectileType ~= nil then
							local frame = IEex_ReadSignedWord(projectileAnimationData + 0xC4, 0x0)
							if frame > 0 then
								IEex_WriteWord(projectileAnimationData + 0xC4, frame - 1)
							end
						end

						if (ex_time_slow_speed_divisor == 0x7FFFFFFF or bit.band(globalEffectFlags, 0x8) > 0) then

							if ex_record_projectile_position[projectileData] == nil then
								ex_record_projectile_position[projectileData] = {IEex_ReadDword(projectileData + 0x6), IEex_ReadDword(projectileData + 0xA)}
							end
							local newX = ex_record_projectile_position[projectileData][1]
							local newY = ex_record_projectile_position[projectileData][2]
							IEex_WriteDword(projectileData + 0x6, newX)
							IEex_WriteDword(projectileData + 0xA, newY)
							IEex_WriteDword(projectileData + 0x9C, newX * 1024 - IEex_ReadDword(projectileData + 0xA4))
							IEex_WriteDword(projectileData + 0xA0, math.floor(newY * 1024 * 4 / 3) - IEex_ReadDword(projectileData + 0xA8))
							IEex_WriteDword(projectileData + 0x116, newX)
							IEex_WriteDword(projectileData + 0x11A, newY)

						end

					end


				end)

				IEex_IterateCastingGlows(targetID, function(share)
					local frame = IEex_ReadSignedWord(share + 0x256, 0x0)
					if frame > 0 then
						IEex_WriteWord(share + 0x256, frame - 1)
					end
				end)


				IEex_IterateFireballs(targetID, function(share)
					local frame = IEex_ReadSignedWord(share + 0x14E, 0x0)
					if frame > 0 then
						IEex_WriteWord(share + 0x14E, frame - 1)
					end
				end)


				IEex_IterateTemporals(targetID, function(temporalData)
					if (ex_time_slow_speed_divisor == 0x7FFFFFFF or bit.band(globalEffectFlags, 0x8) > 0) then

						if IEex_ReadDword(temporalData + 0x94) ~= 0 or IEex_ReadDword(temporalData + 0x98) ~= 0 then
							if ex_record_temporal_position[temporalData] == nil then
								ex_record_temporal_position[temporalData] = {IEex_ReadDword(temporalData + 0x6), IEex_ReadDword(temporalData + 0xA)}
							end
							local newX = ex_record_temporal_position[temporalData][1]
							local newY = ex_record_temporal_position[temporalData][2]
							IEex_WriteDword(temporalData + 0x6, newX)
							IEex_WriteDword(temporalData + 0xA, newY)
							IEex_WriteDword(temporalData + 0x8C, newX * 1024 - IEex_ReadDword(temporalData + 0x94))
							IEex_WriteDword(temporalData + 0x90, newY * 1024 - IEex_ReadDword(temporalData + 0x98))
						end
					end
					local temporalAnimationData = IEex_ReadDword(temporalData + 0x82)
					if temporalAnimationData > 0 then
						local temporalAnimationFrame = IEex_ReadSignedWord(temporalAnimationData + 0x4CA, 0x0)
						if temporalAnimationFrame > 0 then
							IEex_WriteWord(temporalAnimationData + 0x4CA, temporalAnimationFrame - 1)
						end
					end
					local timeRemaining = IEex_ReadSignedWord(temporalData + 0x9C, 0x0)
					local timeElapsed = IEex_ReadSignedWord(temporalData + 0x10E, 0x0)
					if timeElapsed > 0 then
						IEex_WriteWord(temporalData + 0x9C, timeRemaining + 1)
						IEex_WriteWord(temporalData + 0x10E, timeElapsed - 1)
					end
				end)


				IEex_IterateIDs(IEex_ReadDword(creatureData + 0x12), 0x30, function(staticID)
					local staticData = IEex_GetActorShare(staticID)
					local staticFrame = IEex_ReadSignedWord(staticData + 0x17E, 0x0)
					if staticFrame > 0 then
						IEex_WriteWord(staticData + 0x17E, staticFrame - 1)
					end
				end)

			end
		end
		if IEex_ReadWord(creatureData + 0x476, 0x0) == 97 then
			local actionParameter1 = IEex_ReadDword(creatureData + 0x52C)
			if actionParameter1 >= 15 and actionParameter1 <= 17 and IEex_ReadDword(creatureData + 0x4AD8 + actionParameter1 * 0x4) <= 0 then
				IEex_WriteWord(creatureData + 0x476, 0)
			end
		end
		if ex_last_evaluation_tick[targetID] ~= nil then
			timeSinceLastEvaluation = tick - ex_last_evaluation_tick[targetID]
			if timeSinceLastEvaluation <= 0 and timeSinceLastEvaluation >= -2 then return end
		end
		ex_last_evaluation_tick[targetID] = tick
--[[
		if tick % 3 == 0 and not ex_done_reading then
			local resWrapper = IEex_DemandRes("ANIMATE", "IDS")
			if resWrapper:isValid() then
				if ex_current_read_offset == 0 then
					print("ex_animation_size = {")
				end
				local idsData = resWrapper:getData()
				local currentAnimation = ""
				while currentAnimation == "" do
					if IEex_ReadLString(idsData + ex_current_read_offset, 2) == "0x" then
						currentAnimation = IEex_ReadLString(idsData + ex_current_read_offset, 6)
						local animationNumber = ex_hex_to_decimal[IEex_ReadLString(idsData + ex_current_read_offset + 2, 1)] * 0x1000 + ex_hex_to_decimal[IEex_ReadLString(idsData + ex_current_read_offset + 3, 1)] * 0x100 + ex_hex_to_decimal[IEex_ReadLString(idsData + ex_current_read_offset + 4, 1)] * 0x10 + ex_hex_to_decimal[IEex_ReadLString(idsData + ex_current_read_offset + 5, 1)]
						IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 1,
["parameter1"] = animationNumber,
["parameter2"] = 2,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = animationNumber,
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
						local animationData = IEex_ReadDword(creatureData + 0x50F0)
						if animationData > 0 then
							local baseSpeed = IEex_ReadByte(animationData + 0x6, 0x0)
							local circleSize = IEex_ReadDword(animationData + 0x10)
							local personalSpace = IEex_ReadByte(animationData + 0x3E4, 0x0)
--							ex_animation_size[animationNumber] = {circleSize, personalSpace, baseSpeed}
						end
						if currentAnimation == "0xE348" then
							ex_done_reading = true
							for k, v in pairs(ex_animation_size) do
								print("[" .. k .. "] = " .. IEex_ToString(v))
							end
						end
					end
					ex_current_read_offset = ex_current_read_offset + 1
				end
			end
			resWrapper:free()
		end
--]]
	end
	local animation = IEex_ReadDword(creatureData + 0x5C4)

	if bit.band(extraFlags, 0x1000) == 0 then
		extraFlags = bit.bor(extraFlags, 0x1000)
		IEex_WriteDword(creatureData + 0x740, extraFlags)
		local armoredArcanaFeatCount = IEex_ReadByte(creatureData + 0x781, 0x0)
		IEex_WriteByte(creatureData + 0x781, armoredArcanaFeatCount * ex_armored_arcana_multiplier)
	end
	local repermList = {}
	local specialFistWeapon = ""
	local hasShieldEquipped = false
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thespecial = IEex_ReadDword(eData + 0x48)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		if theopcode == 288 and theparameter2 == 224 then
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theresource ~= "" then
				usedFunction = true
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				if theparameter1 <= 0 then
					theparameter1 = 1
				end
				if bit.band(thesavingthrow, 0x100000) == 0 then
					theparameter1 = theparameter1 * 15
				end
				if bit.band(thesavingthrow, 0x400000) == 0 then
					theparent_resource = theresource
				end
				local thecasterlvl = IEex_ReadDword(eData + 0xC8)
				if bit.band(thesavingthrow, 0x200000) > 0 then
					thecasterlvl = IEex_ReadByte(creatureData + 0x626, 0x0)
				end
				local time_applied = IEex_ReadDword(eData + 0x6C)
				if (bit.band(thesavingthrow, 0x1000000) == 0 and tick % theparameter1 == 0) or (bit.band(thesavingthrow, 0x1000000) > 0 and (tick - 1 - time_applied) % theparameter1 == 0) then
					local thesourceid = IEex_ReadDword(eData + 0x110)
					if thesourceid > 0 then
						table.insert(repermList, {theresource, thesourceid, thecasterlvl, theparent_resource})
					else
						table.insert(repermList, {theresource, targetID, thecasterlvl, theparent_resource})
					end
				end
			end
		elseif theopcode == 500 and theresource == "MEFISTWP" then
			specialFistWeapon = IEex_ReadLString(eData + 0x1C, 8)
		elseif theopcode == 288 and theparameter2 == 241 and thespecial == 3 then
			hasShieldEquipped = true
		end
	end)
	local sourceX, sourceY = IEex_GetActorLocation(targetID)
	for k, v in ipairs(repermList) do
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = v[1],
["parent_resource"] = v[4],
["casterlvl"] = v[3],
["target_x"] = sourceX,
["target_y"] = sourceY,
["source_id"] = v[2],
})
	end
	local castingSpeedModifier = 0
	local disableCastingSpeed = false
--	if IEex_GetActorSpellState(targetID, 193) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			if theopcode == 288 and theparameter2 == 193 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local thespecial = IEex_ReadDword(eData + 0x48)
				usedFunction = true
				castingSpeedModifier = castingSpeedModifier + theparameter1
			elseif theopcode == 500 and theresource == "MEIMPALA" then
				disableCastingSpeed = true
			end
		end)
--	end

	local monkLevel = IEex_GetActorStat(targetID, 101)
	local fistWeaponRES = IEex_GetItemSlotRES(targetID, 10)
	local weapon1RES = IEex_GetItemSlotRES(targetID, 43)
	local shield1RES = IEex_GetItemSlotRES(targetID, 44)
	local baseAnimation = IEex_ReadDword(creatureData + 0x5C4)
	if fistWeaponRES ~= "" then
		local correctFistWeaponRES = ex_monk_fist_progression[monkLevel]
		if IEex_GetActorSpellState(targetID, 182) or IEex_GetActorSpellState(targetID, 189) then
			correctFistWeaponRES = ex_incorporeal_monk_fist_progression[monkLevel]
		end
		if specialFistWeapon ~= "" then
			correctFistWeaponRES = specialFistWeapon
		end
		if monkLevel > 0 and (ex_monk_animation_conversion[baseAnimation] ~= nil or baseAnimation == 0x6500 or baseAnimation == 0x6510) and weapon1RES == correctFistWeaponRES and IEex_ReadByte(creatureData + 0x4BA4, 0x0) == 10 and not hasShieldEquipped then
--			IEex_Eval('EquipMostDamagingMelee()',targetID)
			IEex_Eval('SelectWeaponAbility(43,0)',targetID)
			IEex_WriteDword(creatureData + 0x3448, 43)
			IEex_WriteByte(creatureData + 0x4BA4, 43)
			IEex_WriteByte(creatureData + 0x4C68, 0)
			IEex_WriteByte(creatureData + 0x569E, 43)
		elseif monkLevel > 0 and (ex_monk_animation_conversion[baseAnimation] ~= nil or baseAnimation == 0x6500 or baseAnimation == 0x6510) and weapon1RES ~= correctFistWeaponRES and fistWeaponRES == correctFistWeaponRES and shield1RES == "" then
			local alreadyHasWeapon = false
			if weapon1RES ~= "" then
				local resWrapper = IEex_DemandRes(weapon1RES, "ITM")
				if resWrapper:isValid() then
					local itemData = resWrapper:getData()
					local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
					local equippedAppearance = IEex_ReadLString(itemData + 0x22, 2)
					if (itemType ~= 0 and itemType ~= 16 and itemType ~= 19 and itemType ~= 28) or (equippedAppearance ~= "" and equippedAppearance ~= "  ") then
						alreadyHasWeapon = true
					end
				end
				resWrapper:free()
			end
			if not alreadyHasWeapon or not IEex_IsPartyMember(targetID) then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 43,
["resource"] = correctFistWeaponRES,
["parent_resource"] = "USMFIST",
["source_id"] = targetID
})
			end
		elseif fistWeaponRES ~= correctFistWeaponRES and ex_monk_fist_progression[monkLevel] ~= nil then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 10,
["resource"] = correctFistWeaponRES,
["parent_resource"] = "USMFIST",
["source_id"] = targetID
})
		end
--[[
		if not IEex_GetActorSpellState(targetID, 182) and not IEex_GetActorSpellState(targetID, 189) then
			if monkLevel > 0 and (ex_monk_animation_conversion[baseAnimation] ~= nil or baseAnimation == 0x6500 or baseAnimation == 0x6510) and weapon1RES == ex_monk_fist_progression[monkLevel] and IEex_ReadByte(creatureData + 0x4BA4, 0x0) == 10 then
	--			IEex_Eval('EquipMostDamagingMelee()',targetID)
				IEex_Eval('SelectWeaponAbility(43,0)',targetID)
				IEex_WriteDword(creatureData + 0x3448, 43)
				IEex_WriteByte(creatureData + 0x4BA4, 43)
				IEex_WriteByte(creatureData + 0x4C68, 0)
				IEex_WriteByte(creatureData + 0x569E, 43)
			elseif monkLevel > 0 and (ex_monk_animation_conversion[baseAnimation] ~= nil or baseAnimation == 0x6500 or baseAnimation == 0x6510) and weapon1RES ~= ex_monk_fist_progression[monkLevel] and fistWeaponRES == ex_monk_fist_progression[monkLevel] and shield1RES == "" then
				local alreadyHasWeapon = false
				if weapon1RES ~= "" then
					local resWrapper = IEex_DemandRes(weapon1RES, "ITM")
					if resWrapper:isValid() then
						local itemData = resWrapper:getData()
						local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
						local equippedAppearance = IEex_ReadLString(itemData + 0x22, 2)
						if (itemType ~= 0 and itemType ~= 16 and itemType ~= 19 and itemType ~= 28) or (equippedAppearance ~= "" and equippedAppearance ~= "  ") then
							alreadyHasWeapon = true
						end
					end
					resWrapper:free()
				end
				if not alreadyHasWeapon or not IEex_IsPartyMember(targetID) then
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 43,
["resource"] = ex_monk_fist_progression[monkLevel],
["parent_resource"] = "USMFIST",
["source_id"] = targetID
})
				end
			elseif fistWeaponRES ~= ex_monk_fist_progression[monkLevel] and ex_monk_fist_progression[monkLevel] ~= nil then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 10,
["resource"] = ex_monk_fist_progression[monkLevel],
["parent_resource"] = "USMFIST",
["source_id"] = targetID
})
			end
		else
			if monkLevel > 0 and (ex_monk_animation_conversion[baseAnimation] ~= nil or baseAnimation == 0x6500 or baseAnimation == 0x6510) and weapon1RES == ex_incorporeal_monk_fist_progression[monkLevel] and IEex_ReadByte(creatureData + 0x4BA4, 0x0) == 10 then
	--			IEex_Eval('EquipMostDamagingMelee()',targetID)
				IEex_Eval('SelectWeaponAbility(43,0)',targetID)
				IEex_WriteDword(creatureData + 0x3448, 43)
				IEex_WriteByte(creatureData + 0x4BA4, 43)
				IEex_WriteByte(creatureData + 0x4C68, 0)
				IEex_WriteByte(creatureData + 0x569E, 43)
			elseif monkLevel > 0 and (ex_monk_animation_conversion[baseAnimation] ~= nil or baseAnimation == 0x6500 or baseAnimation == 0x6510) and weapon1RES ~= ex_incorporeal_monk_fist_progression[monkLevel] and fistWeaponRES == ex_incorporeal_monk_fist_progression[monkLevel] and shield1RES == "" then
				local alreadyHasWeapon = false
				if weapon1RES ~= "" then
					local resWrapper = IEex_DemandRes(weapon1RES, "ITM")
					if resWrapper:isValid() then
						local itemData = resWrapper:getData()
						local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
						local equippedAppearance = IEex_ReadLString(itemData + 0x22, 2)
						if (itemType ~= 0 and itemType ~= 16 and itemType ~= 19 and itemType ~= 28) or (equippedAppearance ~= "" and equippedAppearance ~= "  ") then
							alreadyHasWeapon = true
						end
					end
					resWrapper:free()
				end
				if not alreadyHasWeapon then
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 43,
["resource"] = ex_incorporeal_monk_fist_progression[monkLevel],
["parent_resource"] = "USMFIST",
["source_id"] = targetID
})
				end
			elseif fistWeaponRES ~= ex_incorporeal_monk_fist_progression[monkLevel] and ex_incorporeal_monk_fist_progression[monkLevel] ~= nil then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 10,
["resource"] = ex_incorporeal_monk_fist_progression[monkLevel],
["parent_resource"] = "USMFIST",
["source_id"] = targetID
})
			end
		end
--]]
	end

	if disableCastingSpeed then
		if castingSpeedModifier > 0 then
			castingSpeedModifier = 0
		end
	end
	if castingSpeedModifier ~= IEex_GetActorStat(targetID, 77) then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USCASTSP",
["source_id"] = targetID
})
		if castingSpeedModifier ~= 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 189,
["target"] = 2,
["timing"] = 9,
["parameter1"] = castingSpeedModifier,
["parent_resource"] = "USCASTSP",
["source_id"] = targetID
})
		end

	end
	if bit.band(extraFlags, 0x10000) == 0 and (IEex_GetActorStat(targetID, 97) > 12 or IEex_GetActorStat(targetID, 105) > 9 or IEex_GetActorStat(targetID, 106) > 8) then
		local spells = IEex_FetchSpellInfo(targetID, {1, 6, 7})
		local sourceHasSpell = false
		for i = 1, 9, 1 do
			for cType, levelList in pairs(spells) do
				if #levelList >= i then
					local levelI = levelList[i]
					local maxCastable = levelI[1]
					local sorcererCastableCount = levelI[2]
					local levelISpells = levelI[3]
					if #levelISpells > 0 then
						for i2, spell in ipairs(levelISpells) do
							if spell["resref"] == "USWI553" then
								sourceHasSpell = true
							end
						end
					end
				end
			end
		end
		if sourceHasSpell then
			extraFlags = bit.bor(extraFlags, 0x10000)
			IEex_WriteDword(creatureData + 0x740, extraFlags)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = "USTIMELS",
["parent_resource"] = "USTIMELS",
["source_id"] = targetID,
})
		end
	end
	if bit.band(extraFlags, 0x20000) == 0 and ex_feat_name_id["ME_EXTEND_SPELL"] then
		extraFlags = bit.bor(extraFlags, 0x20000)
		IEex_WriteDword(creatureData + 0x740, extraFlags)
		local extendSpellFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_EXTEND_SPELL"], 0x0)
		local maximizeSpellFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MAXIMIZE_SPELL"], 0x0)
		local quickenSpellFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_QUICKEN_SPELL"], 0x0)
		local safeSpellFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_SAFE_SPELL"], 0x0)
		if extendSpellFeatCount > 0 and IEex_GetActorSpellState(targetID, 239) then
			IEex_WriteByte(creatureData + 0x744 + ex_feat_name_id["ME_EXTEND_SPELL"], 1)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "FE_" .. ex_feat_name_id["ME_EXTEND_SPELL"] .. "_1",
["source_id"] = targetID,
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 171,
["target"] = 2,
["timing"] = 1,
["resource"] = "USMM003",
["source_id"] = targetID,
})
		end
		if maximizeSpellFeatCount > 0 and IEex_GetActorSpellState(targetID, 238) then
			IEex_WriteByte(creatureData + 0x744 + ex_feat_name_id["ME_MAXIMIZE_SPELL"], 1)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "FE_" .. ex_feat_name_id["ME_MAXIMIZE_SPELL"] .. "_1",
["source_id"] = targetID,
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 171,
["target"] = 2,
["timing"] = 1,
["resource"] = "USMM002",
["source_id"] = targetID,
})
		end
		if quickenSpellFeatCount > 0 and IEex_GetActorSpellState(targetID, 234) then
			IEex_WriteByte(creatureData + 0x744 + ex_feat_name_id["ME_QUICKEN_SPELL"], 1)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "FE_" .. ex_feat_name_id["ME_QUICKEN_SPELL"] .. "_1",
["source_id"] = targetID,
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 171,
["target"] = 2,
["timing"] = 1,
["resource"] = "USMM007",
["source_id"] = targetID,
})
		end
		if safeSpellFeatCount > 0 and IEex_GetActorSpellState(targetID, 235) then
			IEex_WriteByte(creatureData + 0x744 + ex_feat_name_id["ME_SAFE_SPELL"], 1)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "FE_" .. ex_feat_name_id["ME_SAFE_SPELL"] .. "_1",
["source_id"] = targetID,
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 171,
["target"] = 2,
["timing"] = 1,
["resource"] = "USMM004",
["source_id"] = targetID,
})
		end
	end
	if ex_disable_order_multiclass_restrictions then
		IEex_WriteByte(creatureData + 0x89F, bit.band(IEex_ReadByte(creatureData + 0x89F, 0x0), 0xF3))
	end
	return usedFunction
end

function MEBATSNG(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	local bardLevel = IEex_GetActorStat(sourceID, 97)
	local mostRecentBardSong = IEex_ReadByte(creatureData + 0x3D42, 0x0)
	local songRES = tostring(IEex_2DAGetAtStrings("LISTSONG", "SONG_RESREF", tostring(mostRecentBardSong)))
	if songRES == "0" then return end
	for i = 0, 5, 1 do
		local targetID = IEex_GetActorIDCharacter(i)
		if IEex_IsSprite(targetID, false) then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = songRES,
["parent_resource"] = songRES,
["casterlvl"] = bardLevel,
["source_id"] = sourceID
})
		end
	end
end

function MEFISTWP(effectData, creatureData)
	if true then return end
end

function MEBUFFRC(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(sourceID, false) or not IEex_IsPartyMember(sourceID) then return end
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	if IEex_GetGlobal("EX_Recording_Buffs") == 0 then return end
	local partySlot = -1
	for i = 0, 5, 1 do
		if targetID == IEex_GetActorIDCharacter(i) then
			partySlot = i
		end
	end
	local spellNameRef = IEex_GetSpellNameRef(parent_resource)
	local spellName = IEex_FetchString(spellNameRef)
	if spellNameRef <= 0 then
		spellName = IEex_FetchString(ex_tra_55715)
	end
	IEex_SetToken("EXRCSPELL", spellName)
	if partySlot == -1 then
		IEex_DisplayString(IEex_FetchString(ex_tra_55713))
		return
	end
	local special = IEex_ReadDword(effectData + 0x44)
	if special == 0 then
		IEex_SetToken("EXRCTARGET", IEex_GetActorName(targetID))
		IEex_DisplayString(IEex_FetchString(ex_tra_55712))
	else
		IEex_DisplayString(IEex_FetchString(ex_tra_55711))
	end
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 9,
["parameter3"] = partySlot,
["parameter4"] = special,
["resource"] = parent_resource,
["parent_resource"] = "EXBUFFRC",
["source_id"] = sourceID
})
end

function MEBUFFCA(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(sourceID, false) or not IEex_IsPartyMember(sourceID) then return end
	local spellRES = IEex_ReadLString(effectData + 0x6C, 8)
	local partySlot = -1
	for i = 0, 5, 1 do
		if sourceID == IEex_GetActorIDCharacter(i) then
			partySlot = i
		end
	end
	if partySlot == -1 then
		return
	end
	local sourceX, sourceY = IEex_GetActorLocation(sourceID)
	local parameter3 = IEex_ReadDword(effectData + 0x5C)
	local parameter4 = IEex_ReadDword(effectData + 0x60)
	if parameter4 == 0 then
		IEex_Eval('SpellRES(\"' .. spellRES .. '\",Player' .. (parameter3 + 1) .. ')',partySlot)
	else
		IEex_Eval('SpellPointRES(\"' .. spellRES .. '\",[' .. sourceX .. '.' .. sourceY .. '])',partySlot)
	end
--	IEex_Eval('SmallWait(1)',partySlot)
end

function MEONCAST(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(targetID, false) then return end
	local casterlvl = IEex_ReadByte(effectData + 0xC4, 0x0)
	local parent_resource = IEex_ReadLString(effectData + 0x18, 8)
	if IEex_GetGlobal("EX_Recording_Buffs") == 1 then
		local actionID = IEex_Helper_GetBridge("IEex_RecordSpell", targetID, "actionID")
		local spellTargetID = IEex_Helper_GetBridge("IEex_RecordSpell", targetID, "targetID")
		if actionID == 31 and spellTargetID ~= nil and IEex_IsSprite(spellTargetID, false) then
			IEex_ApplyEffectToActor(spellTargetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 0,
["resource"] = "MEBUFFRC",
["parent_resource"] = parent_resource,
["source_id"] = targetID
})
		elseif actionID == 95 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 1,
["resource"] = "MEBUFFRC",
["parent_resource"] = parent_resource,
["source_id"] = targetID
})
		end
	end
	local lowestClassSpellLevel = 10
	local classSpellLevel = 0
	for i = 2, 11, 1 do
		if IEex_GetActorStat(targetID, 95 + i) > 0 then
			classSpellLevel = IEex_GetClassSpellLevel(targetID, i, parent_resource)
			if classSpellLevel > 0 and classSpellLevel < lowestClassSpellLevel then
				lowestClassSpellLevel = classSpellLevel
				casterlvl = IEex_GetActorStat(targetID, 95 + i)
			end
		end
	end
	classSpellLevel = lowestClassSpellLevel

	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USFREESP",
["source_id"] = targetID
})
	local maximumQuickenSpellLevel = 0
--	if IEex_GetActorSpellState(targetID, 234) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 234 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				if theresource ~= "" and theresource == parent_resource then
					maximumQuickenSpellLevel = 99
				else
					maximumQuickenSpellLevel = maximumQuickenSpellLevel + theparameter1
				end
			end
		end)
--	end
	if classSpellLevel > 0 and maximumQuickenSpellLevel >= classSpellLevel then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 188,
["target"] = 2,
["timing"] = 0,
["duration"] = 6,
["parameter2"] = 1,
["parent_resource"] = "USFREESP",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 6,
["resource"] = "USFREESP",
["parent_resource"] = "USFREESP",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 6,
["resource"] = "USFREESP",
["parent_resource"] = "USFREES2",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 6,
["resource"] = "USFREES2",
["parent_resource"] = "USFREES2",
["source_id"] = targetID
})
	end

	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USDURMAG",
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USDURPRI",
["source_id"] = targetID
})
	local maximumExtendSpellLevel = 0
--	if IEex_GetActorSpellState(targetID, 239) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 239 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				if theresource ~= "" and theresource == parent_resource then
					maximumExtendSpellLevel = 99
				else
					maximumExtendSpellLevel = maximumExtendSpellLevel + theparameter1
				end
			end
		end)
--	end
--[[
	if classSpellLevel > 0 and maximumExtendSpellLevel >= classSpellLevel then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 200,
["parameter2"] = 195,
["parent_resource"] = "USDURMAG",
["source_id"] = targetID
})
	end
--]]
--[[
	local wizardDurationModifier = 100
	local priestDurationModifier = 100
--	if IEex_GetActorSpellState(targetID, 193) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 193 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local thespecial = IEex_ReadDword(eData + 0x48)
				local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
				if thespecial == 0 then
					wizardDurationModifier = math.floor(wizardDurationModifier * theparameter1 / 100)
				elseif thespecial == 1 then
					priestDurationModifier = math.floor(priestDurationModifier * theparameter1 / 100)
				end
			end
		end)
--	end
	if classSpellLevel > 0 and maximumExtendSpellLevel >= classSpellLevel then
		wizardDurationModifier = wizardDurationModifier * 2
		priestDurationModifier = priestDurationModifier * 2
	end
	if wizardDurationModifier > 255 then
		wizardDurationModifier = 255
	end
	if priestDurationModifier > 255 then
		priestDurationModifier = 255
	end
	if ex_fixed_duration_spell_list[parent_resource] then
		wizardDurationModifier = 100
		priestDurationModifier = 100
	end
	if wizardDurationModifier ~= 100 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 99,
["target"] = 2,
["timing"] = 9,
["parameter1"] = wizardDurationModifier,
["parent_resource"] = "USDURMAG",
["source_id"] = targetID
})
	end
	if priestDurationModifier ~= 100 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 99,
["target"] = 2,
["timing"] = 9,
["parameter1"] = priestDurationModifier,
["parameter2"] = 1,
["parent_resource"] = "USDURPRI",
["source_id"] = targetID
})
	end
--]]
--	if IEex_GetActorSpellState(targetID, 227) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 227 then
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				if theresource ~= "" then
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = theresource,
["casterlvl"] = casterlvl,
["source_id"] = targetID
})
				end
			end
		end)
--	end
end

function MESAFESP(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local casterlvl = IEex_ReadByte(effectData + 0xC4, 0x0)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local sourceSpell = IEex_ReadLString(effectData + 0x18, 8)
	if sourceSpell == "" then
		sourceSpell = parent_resource
	end
	local classSpellLevel = IEex_GetClassSpellLevel(targetID, casterClass, sourceSpell)
	local maximumSafeSpellLevel = 0
--	if IEex_GetActorSpellState(sourceID, 235) then
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 235 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				if theresource ~= "" and theresource == sourceSpell then
					maximumSafeSpellLevel = 99
				else
					maximumSafeSpellLevel = maximumSafeSpellLevel + theparameter1
				end
			end
		end)
--	end
	local allowAbsorption = false
	if bit.band(savingthrow, 0x20000) > 0 and IEex_GetActorSpellState(targetID, 214) then
		local damageTypeAllowed = IEex_ReadDword(effectData + 0x44)
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 214 and theparameter1 == damageTypeAllowed then
				allowAbsorption = true
			end
		end)
	end
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
--[[
	if bit.band(savingthrow, 0x100000) > 0 then
		IEex_IterateProjectiles(targetID, 108, function(share)
			if IEex_ReadDword(share + 0x72) == sourceID then
				if ex_projectile_flags[share] ~= nil then
					internalFlags = bit.bor(ex_projectile_flags[share]["Metamagic"], 0x20)
				end
			end
		end)
	end
--]]
	if (bit.band(internalFlags, 0x80000) > 0 or (classSpellLevel > 0 and maximumSafeSpellLevel >= classSpellLevel)) and allowAbsorption == false then
		if bit.band(savingthrow, 0x10000) == 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 290,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter2"] = 49,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		else
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter2"] = 49,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		end
	end
end

function MELRNALL(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local wizardLevel = IEex_ReadByte(creatureData + 0x631, 0x0)
	if wizardLevel == 0 then return end
	local maxLevel = IEex_ReadSignedWord(effectData + 0x18, 0x0)
	local minLevel = IEex_ReadSignedWord(effectData + 0x1A, 0x0)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local matchSchool = IEex_ReadDword(effectData + 0x44)
	if maxLevel < 1 or maxLevel > 9 then
		maxLevel = 9
	end
	if minLevel < 1 or minLevel > 9 then
		minLevel = 1
	end
	local kit = IEex_GetActorStat(targetID, 89)
	local specialistBit = 0x40
	local specialistSchool = 0
	for i = 1, 8, 1 do
		if bit.band(kit, specialistBit) > 0 then
			specialistSchool = i
		end
		specialistBit = specialistBit * 2
	end
	if specialistSchool == 0 then return end
	if bit.band(savingthrow, 0x10000) > 0 then
		matchSchool = specialistSchool
	end
	local matchSchools = {[1] = false, [2] = false, [3] = false, [4] = false, [5] = false, [6] = false, [7] = false, [8] = false, [9] = false, }
	if matchSchool == -1 then
		matchSchools = {[1] = true, [2] = true, [3] = true, [4] = true, [5] = true, [6] = true, [7] = true, [8] = true, [9] = true, }
		if bit.band(savingthrow, 0x20000) == 0 then
			if specialistSchool == 1 then
				matchSchools[6] = false
			elseif specialistSchool == 2 then
				matchSchools[7] = false
			elseif specialistSchool == 3 then
				matchSchools[5] = false
			elseif specialistSchool == 4 then
				matchSchools[8] = false
			elseif specialistSchool == 5 then
				matchSchools[3] = false
			elseif specialistSchool == 6 then
				matchSchools[1] = false
			elseif specialistSchool == 7 then
				matchSchools[2] = false
			elseif specialistSchool == 8 then
				matchSchools[4] = false
			end
		end
	elseif matchSchool >= 1 and matchSchool <= 9 then
		matchSchools[matchSchool] = true
	end
	for spellRES, levels in pairs(ex_listspll) do
		if levels[7] > 0 and matchSchools[ex_trueschool[spellRES]] then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 147,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["source_id"] = targetID
})
		end
	end
	if bit.band(savingthrow, 0x40000) > 0 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 9,
["parameter2"] = 250,
["savingthrow"] = 0x10000,
["special"] = specialistSchool + 0x20000,
["resource"] = "MEBARCAS",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 9,
["parameter2"] = 250,
["savingthrow"] = 0x10000,
["special"] = specialistSchool + 0xA0000,
["resource"] = "MEBARCAS",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 9,
["parameter2"] = 250,
["savingthrow"] = 0x10000,
["special"] = specialistSchool + 0xB0000,
["resource"] = "MEBARCAS",
["source_id"] = targetID
})
	end
end

function MESTEALE(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(sourceID, false) or sourceID == targetID then return end
	local effectsStolen = {}
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local thepower = IEex_ReadDword(eData + 0x18)
		local theparameter1 = IEex_ReadDword(eData + 0x1C)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thetiming = IEex_ReadDword(eData + 0x24)
		local theduration = IEex_ReadDword(eData + 0x28)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local thesavebonus = IEex_ReadDword(eData + 0x44)
		local thespecial = IEex_ReadDword(eData + 0x48)
		local theresist_dispel = IEex_ReadDword(eData + 0x5C)
		local thetime_applied = IEex_ReadDword(eData + 0x6C)
		local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
		if (thetiming == 6 or thetiming == 7 or thetiming == 4096) and (theresist_dispel == 1 or theresist_dispel == 3) and (ex_listspll[theparent_resource] ~= nil or ex_true_spell[theparent_resource] ~= nil or ex_source_spell[theparent_resource] ~= nil) then
			if thetiming == 6 then
				thetiming = 3
			elseif thetiming == 7 then
				thetiming = 4
			elseif thetiming == 4096 then
				thetiming = 0
			end
			theduration = math.floor((theduration - thetime_applied) / 15)
			if theopcode == 119 then
				theopcode = 500
				theresource = "MEMIRRIM"
				thespecial = theduration
				theduration = 0
			end
			table.insert(effectsStolen, {
["opcode"] = theopcode,
["target"] = 2,
["power"] = IEex_ReadDword(eData + 0x18),
["parameter1"] = theparameter1,
["parameter2"] = theparameter2,
["timing"] = thetiming,
["duration"] = theduration,
["resource"] = theresource,
["dicenumber"] = IEex_ReadDword(eData + 0x38),
["dicesize"] = IEex_ReadDword(eData + 0x3C),
["savingthrow"] = IEex_ReadDword(eData + 0x40),
["savebonus"] = IEex_ReadDword(eData + 0x44),
["special"] = thespecial,
["school"] = IEex_ReadDword(eData + 0x4C),
["resist_dispel"] = 3,
["parameter3"] = IEex_ReadDword(eData + 0x60),
["parameter4"] = IEex_ReadDword(eData + 0x64),
["parameter5"] = IEex_ReadDword(eData + 0x68),
["time_applied"] = thetime_applied,
["vvcresource"] = IEex_ReadLString(eData + 0x70, 8),
["resource2"] = IEex_ReadLString(eData + 0x78, 8),
["source_x"] = IEex_ReadDword(eData + 0x80),
["source_y"] = IEex_ReadDword(eData + 0x84),
["target_x"] = IEex_ReadDword(eData + 0x88),
["target_y"] = IEex_ReadDword(eData + 0x8C),
["restype"] = IEex_ReadDword(eData + 0x90),
["parent_resource"] = IEex_ReadLString(eData + 0x94, 8),
["resource_flags"] = bit.band(IEex_ReadDword(eData + 0x9C), 0xFFFFF9FF),
["impact_projectile"] = IEex_ReadDword(eData + 0xA0),
["sourceslot"] = IEex_ReadDword(eData + 0xA4),
["effvar"] = IEex_ReadLString(eData + 0xA8, 32),
["casterlvl"] = IEex_ReadDword(eData + 0xC8),
["internal_flags"] = bit.bor(IEex_ReadDword(eData + 0xD0), IEex_ReadDword(eData + 0xD8)),
["sectype"] = IEex_ReadDword(eData + 0xD8),
["source_id"] = IEex_ReadDword(eData + 0x110),
})
		end
	end)
	for k, the_effect in ipairs(effectsStolen) do
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = the_effect["opcode"],
["target"] = the_effect["target"],
["power"] = the_effect["power"],
["parameter1"] = the_effect["parameter1"],
["parameter2"] = the_effect["parameter2"],
["timing"] = the_effect["timing"],
["duration"] = the_effect["duration"],
["resource"] = the_effect["resource"],
["dicenumber"] = the_effect["dicenumber"],
["dicesize"] = the_effect["dicesize"],
["savingthrow"] = the_effect["savingthrow"],
["savebonus"] = the_effect["savebonus"],
["special"] = the_effect["special"],
["school"] = the_effect["school"],
["parameter3"] = the_effect["parameter3"],
["parameter4"] = the_effect["parameter4"],
["parameter5"] = the_effect["parameter5"],
["vvcresource"] = the_effect["vvcresource"],
["resource2"] = the_effect["resource2"],
["source_x"] = the_effect["source_x"],
["source_y"] = the_effect["source_y"],
["target_x"] = the_effect["target_x"],
["target_y"] = the_effect["target_y"],
["restype"] = the_effect["restype"],
["parent_resource"] = the_effect["parent_resource"],
["resource_flags"] = the_effect["resource_flags"],
["impact_projectile"] = the_effect["impact_projectile"],
["sourceslot"] = the_effect["sourceslot"],
["effvar"] = the_effect["effvar"],
["casterlvl"] = the_effect["casterlvl"],
["internal_flags"] = the_effect["internal_flags"],
["sectype"] = the_effect["sectype"],
["source_id"] = the_effect["source_id"],
})
	end
end

--[[
To use the EXMODMEM function, create an opcode 500 effect in an item or spell, set the resource to EXMODMEM (all capitals),
 set the timing to instant, limited and the duration to 0, and choose parameters.

The EXMODMEM function changes which spells the target can cast. It can either restore spell uses or
 deplete spell uses. By default, it can only restore/remove spells of the same caster type as the spell that called this function
 (e.g. if this was cast as a bard spell, it will only restore/remove spells in the character's bard spell list) unless extra bits are
 set on the savingthrow parameter.

parameter1 - Determines the maximum number of spell uses that can be restored. If negative, it removes spells instead.

parameter2 - Determines the highest spell level that can be restored (1 - 9).

savingthrow - This function uses several extra bits on this parameter:
Bit 16: If set, the function can restore/remove bard spells.
Bit 17: If set, the function can restore/remove cleric spells.
Bit 18: If set, the function can restore/remove druid spells.
Bit 19: If set, the function can restore/remove paladin spells.
Bit 20: If set, the function can restore/remove ranger spells.
Bit 21: If set, the function can restore/remove sorcerer spells.
Bit 22: If set, the function can restore/remove wizard spells.
Bit 23: If set, the function can restore/remove domain spells.
Bit 25: If set, the function will only restore the spell specified in the "vvcresource" (referred to as Resource2 in NearInfinity).
Bit 27: If set, the function generates feedback on which spells were restored/removed.

special - Determines the lowest spell level that can be restored (1 - 9).
--]]

function EXMODMEM(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	IEex_WriteDword(effectData + 0x110, 1)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local modifyRemaining = IEex_ReadDword(effectData + 0x18)
	local maxLevel = IEex_ReadWord(effectData + 0x1C, 0x0)
	local minLevel = IEex_ReadWord(effectData + 0x44, 0x0)
	local maxStolenLevel = IEex_ReadWord(effectData + 0x1E, 0x0)
	local minStolenLevel = IEex_ReadWord(effectData + 0x46, 0x0)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterlvl = IEex_ReadByte(effectData + 0xC4, 0x0)
	local matchSpell = IEex_ReadLString(effectData + 0x6C, 8)
	if matchSpell == "" then
		matchSpell = parent_resource
	end
--[[
	local ignoreSpell = IEex_ReadLString(effectData + 0x74, 8)
	if ignoreSpell == "" then
		ignoreSpell = parent_resource
	end
--]]
	local subtractSpells = false
	if modifyRemaining < 0 then
		subtractSpells = true
		modifyRemaining = math.abs(modifyRemaining)
	end
	if (maxStolenLevel > 0 and minStolenLevel > 0) then
		subtractSpells = true
		if bit.band(savingthrow, 0x1000000) > 0 then
			modifyRemaining = modifyRemaining + math.floor((math.random(20) + casterlvl + IEex_GetActorStat(sourceID, 29)) / 10)
		end
	end
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	local casterType = IEex_CasterClassToType[casterClass]
	local casterTypes = {}
	if casterType ~= nil then
		if bit.band(savingthrow, 2 ^ (casterType + 15)) == 0 then
			table.insert(casterTypes, casterType)
		end
	end
	if bit.band(savingthrow, 0x800000) > 0 then
		table.insert(casterTypes, 8)
	end
	for i = 1, 7, 1 do
		if bit.band(savingthrow, 2 ^ (i + 15)) > 0 then
			table.insert(casterTypes, i)
		end
	end
	local modifyList = {}
	local spellsStolen = 0
	local spells = IEex_FetchSpellInfo(targetID, casterTypes)
	for i = maxLevel, minLevel, -1 do
		for cType, levelList in pairs(spells) do
			if #levelList >= i then
				local levelI = levelList[i]
				local maxCastable = levelI[1]
				local sorcererCastableCount = levelI[2]
				local levelISpells = levelI[3]
				if #levelISpells > 0 then
					if cType == 1 or cType == 6 then
						local matchSpellFound = true
						if bit.band(savingthrow, 0x2000000) > 0 then
							matchSpellFound = false
							for i2, spell in ipairs(levelISpells) do
								if matchSpell == spell["resref"] then
									matchSpellFound = true
								end
							end
						end
						if matchSpellFound then
							if not subtractSpells then
								local modifyNum = maxCastable - sorcererCastableCount
								if modifyNum > modifyRemaining then
									modifyNum = modifyRemaining
								end
								if modifyNum > 0 then
									modifyRemaining = modifyRemaining - modifyNum
									table.insert(modifyList, {i, modifyNum, ""})
									IEex_AlterSpellInfo(targetID, cType, i, "", 0, modifyNum)
								end
							else
								local modifyNum = sorcererCastableCount
								if modifyNum > modifyRemaining then
									modifyNum = modifyRemaining
								end
								if modifyNum > 0 then
									modifyRemaining = modifyRemaining - modifyNum
									spellsStolen = spellsStolen + modifyNum
									table.insert(modifyList, {i, modifyNum, ""})
									IEex_AlterSpellInfo(targetID, cType, i, "", 0, modifyNum * -1)
								end
							end
						end
					else
						for i2, spell in ipairs(levelISpells) do
							if bit.band(savingthrow, 0x2000000) == 0 or matchSpell == spell["resref"] then
								if not subtractSpells then
									local modifyNum = spell["memorizedCount"] - spell["castableCount"]
									if modifyNum > modifyRemaining then
										modifyNum = modifyRemaining
									end
									if modifyNum > 0 then
										modifyRemaining = modifyRemaining - modifyNum
										table.insert(modifyList, {i, modifyNum, spell["resref"]})
										IEex_AlterSpellInfo(targetID, cType, i, spell["resref"], 0, modifyNum)
									end
								else
									local modifyNum = spell["castableCount"]
									if modifyNum > modifyRemaining then
										modifyNum = modifyRemaining
									end
									if modifyNum > 0 then
										modifyRemaining = modifyRemaining - modifyNum
										spellsStolen = spellsStolen + modifyNum
										table.insert(modifyList, {i, modifyNum, spell["resref"]})
										IEex_AlterSpellInfo(targetID, cType, i, spell["resref"], 0, modifyNum * -1)
									end
								end
							end
						end
					end
				end
			end
		end
	end
	if bit.band(savingthrow, 0x2000000) > 0 then
		local abilities = IEex_FetchSpellInfo(targetID, {9})
		local levelList = abilities[9]
		local levelISpells = levelList[1]
		for i2, spell in ipairs(levelISpells) do
			if matchSpell == spell["resref"] then
				if not subtractSpells then
					local modifyNum = spell["memorizedCount"] - spell["castableCount"]
					if modifyNum > modifyRemaining then
						modifyNum = modifyRemaining
					end
					if modifyNum > 0 then
						modifyRemaining = modifyRemaining - modifyNum
--						table.insert(modifyList, {i, modifyNum, spell["resref"]})
						IEex_AlterSpellInfo(targetID, 9, 1, spell["resref"], 0, modifyNum)
					end
				else
					local modifyNum = spell["castableCount"]
					if modifyNum > modifyRemaining then
						modifyNum = modifyRemaining
					end
					if modifyNum > 0 then
						modifyRemaining = modifyRemaining - modifyNum
--						table.insert(modifyList, {i, modifyNum, spell["resref"]})
						IEex_AlterSpellInfo(targetID, 9, 1, spell["resref"], 0, modifyNum * -1)
					end
				end
			end
		end
	end
	if bit.band(savingthrow, 0x8000000) > 0 then
		local feedbackString = ""
		for i = 1, #modifyList, 1 do
			if modifyList[i][2] == 1 then
				feedbackString = feedbackString .. ex_str_55431
			else
				feedbackString = feedbackString .. ex_str_55432
			end
			if i == 1 then
				if not subtractSpells then
					feedbackString = string.gsub(feedbackString, "<EXSSREGAINEDLOSTAND>", ex_str_55453)
				else
					feedbackString = string.gsub(feedbackString, "<EXSSREGAINEDLOSTAND>", ex_str_55454)
				end
			elseif i == #modifyList then
				feedbackString = string.gsub(feedbackString, "<EXSSREGAINEDLOSTAND>", ex_str_55455)
			else
				feedbackString = string.gsub(feedbackString, "<EXSSREGAINEDLOSTAND>", "")
			end
			feedbackString = string.gsub(feedbackString, "<EXSSNUMSPELLS>", modifyList[i][2])
			if modifyList[i][3] == "" then
				feedbackString = string.gsub(feedbackString, "<EXSSLEVELORNAME>", IEex_FetchString(ex_spelllevelstrrefs[modifyList[i][1]]))
			else
				local resWrapper = IEex_DemandRes(modifyList[i][3], "SPL")
				if resWrapper:isValid() then
					local spellData = resWrapper:getData()
					feedbackString = string.gsub(feedbackString, "<EXSSLEVELORNAME>", IEex_FetchString(IEex_ReadDword(spellData + 0x8)))
				else
					feedbackString = string.gsub(feedbackString, "<EXSSLEVELORNAME>", "unknown")
				end
				resWrapper:free()
			end
			if i ~= #modifyList then
				feedbackString = feedbackString .. ",\n"
			end
		end
		IEex_SetToken("EXSSFULL1", feedbackString)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = ex_tra_55401,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
	end
	if maxStolenLevel > 0 and minStolenLevel > 0 and spellsStolen > 0 and IEex_IsSprite(sourceID, true) then
		modifyRemaining = spellsStolen
		subtractSpells = false
		modifyList = {}
		spells = IEex_FetchSpellInfo(sourceID, casterTypes)
		for i = maxStolenLevel, minStolenLevel, -1 do
			for cType, levelList in pairs(spells) do
				if #levelList >= i then
					local levelI = levelList[i]
					local maxCastable = levelI[1]
					local sorcererCastableCount = levelI[2]
					local levelISpells = levelI[3]
					if #levelISpells > 0 then
						if cType == 1 or cType == 6 then
							local modifyNum = maxCastable - sorcererCastableCount
							if modifyNum > modifyRemaining then
								modifyNum = modifyRemaining
							end
							if modifyNum > 0 then
								modifyRemaining = modifyRemaining - modifyNum
								table.insert(modifyList, {i, modifyNum, ""})
								IEex_AlterSpellInfo(sourceID, cType, i, "", 0, modifyNum)
							end
						else
							for i2, spell in ipairs(levelISpells) do
								local modifyNum = spell["memorizedCount"] - spell["castableCount"]
								if modifyNum > modifyRemaining then
									modifyNum = modifyRemaining
								end
								if modifyNum > 0 then
									modifyRemaining = modifyRemaining - modifyNum
									table.insert(modifyList, {i, modifyNum, spell["resref"]})
									IEex_AlterSpellInfo(sourceID, cType, i, spell["resref"], 0, modifyNum)
								end
							end
						end
					end
				end
			end
		end
		if bit.band(savingthrow, 0x8000000) > 0 and #modifyList > 0 then
			local feedbackString = ""
			for i = 1, #modifyList, 1 do
				if modifyList[i][2] == 1 then
					feedbackString = feedbackString .. ex_str_55431
				else
					feedbackString = feedbackString .. ex_str_55432
				end
				if i == 1 then
					if not subtractSpells then
						feedbackString = string.gsub(feedbackString, "<EXSSREGAINEDLOSTAND>", ex_str_55453)
					else
						feedbackString = string.gsub(feedbackString, "<EXSSREGAINEDLOSTAND>", ex_str_55454)
					end
				elseif i == #modifyList then
					feedbackString = string.gsub(feedbackString, "<EXSSREGAINEDLOSTAND>", ex_str_55455)
				else
					feedbackString = string.gsub(feedbackString, "<EXSSREGAINEDLOSTAND>", "")
				end
				feedbackString = string.gsub(feedbackString, "<EXSSNUMSPELLS>", modifyList[i][2])
				if modifyList[i][3] == "" then
					feedbackString = string.gsub(feedbackString, "<EXSSLEVELORNAME>", IEex_FetchString(ex_spelllevelstrrefs[modifyList[i][1]]))
				else
					local resWrapper = IEex_DemandRes(modifyList[i][3], "SPL")
					if resWrapper:isValid() then
						local spellData = resWrapper:getData()
						feedbackString = string.gsub(feedbackString, "<EXSSLEVELORNAME>", IEex_FetchString(IEex_ReadDword(spellData + 0x8)))
					else
						feedbackString = string.gsub(feedbackString, "<EXSSLEVELORNAME>", "unknown")
					end
					resWrapper:free()
				end
				if i ~= #modifyList then
					feedbackString = feedbackString .. ",\n"
				end
			end
			IEex_SetToken("EXSSFULL2", feedbackString)
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = ex_tra_55402,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		end
	end
end

--[[
MESPLPRT works similarly to opcode 290. It grants immunity to the spell if the target satisfies a condition.

Values for special:
0: The target gets immunity if they have protection from the opcode specified by parameter2.
1: The target gets immunity if they have protection from the spell specified by parameter1 and parameter2.
2: The target gets immunity if they have any of the states specified by parameter2.
3: The target gets immunity if they have the spell state specified by parameter2.
4: The target gets immunity if their stat specified by parameter2 satisfies a condition based on the last byte of parameter2.
5:
6: The target gets immunity if they have any of the races specified by parameter2.
7: The target gets immunity if they have any of the general types (e.g. undead) specified by parameter2.
--]]
function MESPLPRT(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	IEex_WriteDword(effectData + 0x110, 1)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local sourceData = IEex_GetActorShare(sourceID)
	local targetID = IEex_GetActorIDShare(creatureData)
	local checkID = targetID
	local newEffectTarget = targetID
	local hasProtection = false
	local protectionType = IEex_ReadDword(effectData + 0x44)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if bit.band(savingthrow, 0x20000) > 0 and IEex_IsSprite(sourceID, true) then
		checkID = sourceID
	end
	if bit.band(savingthrow, 0x200000) > 0 then
		newEffectTarget = sourceID
	end
	local checkData = IEex_GetActorShare(checkID)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	if protectionType == 0 then
		local match_opcode = IEex_ReadDword(effectData + 0x1C)
		local targetRace = IEex_ReadByte(checkData + 0x26, 0x0)
		local targetSubrace = IEex_ReadByte(checkData + 0x7FF, 0x0)
		if (match_opcode == 39 and (targetRace == 2 or targetRace == 3 or targetRace == 183)) or ((match_opcode == 109 or match_opcode == 175) and ((targetRace == 4 and targetSubrace == 2) or targetRace == 185)) then
			hasProtection = true
		elseif ((match_opcode == 55 or match_opcode == 420) and IEex_GetActorSpellState(checkID, 8)) or ((match_opcode == 40 or match_opcode == 109 or match_opcode == 154 or match_opcode == 157 or match_opcode == 158 or match_opcode == 175 or match_opcode == 176) and IEex_GetActorSpellState(checkID, 29)) then
			hasProtection = true
		elseif ((match_opcode == 24 or match_opcode == 236) and IEex_GetActorStat(checkID, 102) >= 2) or (match_opcode == 25 and (IEex_GetActorStat(checkID, 99) >= 9 or IEex_GetActorStat(checkID, 101) >= 11)) or (match_opcode == 78 and (IEex_GetActorStat(checkID, 101) >= 5 or IEex_GetActorStat(checkID, 102) >= 1)) then
			hasProtection = true
		elseif (match_opcode == 5 or match_opcode == 412) and IEex_GetActorSpellState(checkID, 1) and sourceData > 0 and bit.band(IEex_ReadByte(sourceData + 0x35, 0x0), 0x3) == 0x3 then
			hasProtection = true
		else
			IEex_IterateActorEffects(checkID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				if (theopcode == 101 or theopcode == 261) and theparameter2 == match_opcode then
					hasProtection = true
				end
			end)
		end
	elseif protectionType == 1 then
		local protectionRES = IEex_ReadLString(effectData + 0x18, 8)
		IEex_IterateActorEffects(checkID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			if (theopcode == 206 or theopcode == 290) and theresource == protectionRES then
				hasProtection = true
			end
		end)
	elseif protectionType == 2 then
		local match_state = IEex_ReadDword(effectData + 0x1C)
		local stateValue = bit.bor(IEex_ReadDword(checkData + 0x5BC), IEex_ReadDword(checkData + 0x920))
		if bit.band(stateValue, match_state) > 0 then
			hasProtection = true
		end
	elseif protectionType == 3 then
		local match_spellState = IEex_ReadDword(effectData + 0x1C)
		if IEex_GetActorSpellState(checkID, match_spellState) then
			hasProtection = true
		end
	elseif protectionType == 4 then
		local match_value = IEex_ReadDword(effectData + 0x18)
		local match_stat = IEex_ReadWord(effectData + 0x1C, 0x0)
		local statOperator = IEex_ReadByte(effectData + 0x1F, 0x0)
		local statValue = IEex_GetActorStat(checkID, match_stat)
		if (statOperator == 0 and statValue >= match_value) or (statOperator == 1 and statValue == match_value) or (statOperator == 2 and bit.band(statValue, match_value) == match_value) or (statOperator == 3 and bit.band(statValue, match_value) > 0) then
			hasProtection = true
		end
	elseif protectionType == 5 then
		local match_value = IEex_ReadDword(effectData + 0x18)
		local match_offset = IEex_ReadWord(effectData + 0x1C, 0x0)
		local readSize = IEex_ReadByte(effectData + 0x1E, 0x0)
		local statOperator = IEex_ReadByte(effectData + 0x1F, 0x0)
		local statValue = 0
		if readSize == 2 then
			statValue = IEex_ReadSignedWord(checkData + match_offset, 0x0)
		elseif readSize == 4 then
			statValue = IEex_ReadDword(checkData + match_offset)
		elseif readSize > 4 then
			statValue = IEex_ReadLString(checkData + match_offset, readSize)
		else
			statValue = IEex_ReadSignedByte(checkData + match_offset, 0x0)
		end
		if (statOperator == 0 and statValue >= match_value) or (statOperator == 1 and statValue == match_value) or (statOperator == 2 and bit.band(statValue, match_value) == match_value) or (statOperator == 3 and bit.band(statValue, match_value) > 0) then
			hasProtection = true
		end
	elseif protectionType == 6 then
		local race = IEex_ReadByte(checkData + 0x26, 0x0)
		local match_race1 = IEex_ReadByte(effectData + 0x1C, 0x0)
		local match_race2 = IEex_ReadByte(effectData + 0x1D, 0x0)
		local match_race3 = IEex_ReadByte(effectData + 0x1E, 0x0)
		local match_race4 = IEex_ReadByte(effectData + 0x1F, 0x0)
		if race == match_race1 or race == match_race2 or race == match_race3 or race == match_race4 then
			hasProtection = true
		end
	elseif protectionType == 7 then
		local general = IEex_ReadByte(checkData + 0x25, 0x0)
		local match_general1 = IEex_ReadByte(effectData + 0x1C, 0x0)
		local match_general2 = IEex_ReadByte(effectData + 0x1D, 0x0)
		local match_general3 = IEex_ReadByte(effectData + 0x1E, 0x0)
		local match_general4 = IEex_ReadByte(effectData + 0x1F, 0x0)
		if general == match_general1 or general == match_general2 or general == match_general3 or general == match_general4 then
			hasProtection = true
		end
	elseif protectionType == 8 then
		local match_value = IEex_ReadDword(effectData + 0x18)
		local match_stat = IEex_ReadWord(effectData + 0x1C, 0x0)
		local statOperator = IEex_ReadByte(effectData + 0x1F, 0x0)
		local statValue = math.abs(IEex_GetActorStat(targetID, match_stat) - IEex_GetActorStat(sourceID, match_stat))
		if (statOperator == 0 and statValue >= match_value) or (statOperator == 1 and statValue == match_value) or (statOperator == 2 and bit.band(statValue, match_value) == match_value) or (statOperator == 3 and bit.band(statValue, match_value) > 0) then
			hasProtection = true
		end
	elseif protectionType == 9 then
		local ea = IEex_ReadByte(checkData + 0x25, 0x0)
		local match_ea1 = IEex_ReadByte(effectData + 0x1C, 0x0)
		local matchEA = {[match_ea1] = true}
		if ex_ea_wildcards[match_ea1] ~= nil then
			matchEA = ex_ea_wildcards[match_ea1]
		end
		if matchEA[ea] then
			hasProtection = true
		end
	elseif protectionType == 10 then
		if IEex_IsPartyMember(checkID) then
			hasProtection = true
		end
	end
	local invert = (bit.band(savingthrow, 0x100000) > 0)
	if (hasProtection == true and invert == false) or (hasProtection == false and invert == true) then
		if bit.band(savingthrow, 0x10000) == 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 290,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		else
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		end
	end
end
--[[
MESPLPR2 works similarly to opcodes 206 and 290. It grants immunity to the spell if the target satisfies a condition.

parameter2 - Determines the condition. If it's true, the target is immune to the spell. The conditions are the same as with
 opcodes 206 and 290, but will take things like Better Racial Enemies into account. There are some extras added at the end, though.
 Here are some of them:
 55: Unnatural (undead, construct, object, or extraplanar creature)
 94: Nonliving (undead, construct, or object)
 96: Mindless (undead, construct, object, shambling mound, or ooze)
 98: Drow or duergar
 100: Light-sensitive (drow, duergar, fungi, shadows, wights, and wraiths)
 102: Fiend
 104: Fiend or undead
 106: Airborne
 108: Incorporeal or ethereal
 110: Yuan-ti
 112: Humanoid or giant humanoid
 114: Undead, construct, or demon
 116: Shield or off-hand weapon equipped
 118: Object or construct
 120: Living allies
 122: Living enemies
 124: Undead allies
 126: Undead enemies

--]]
function MESPLPR2(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	IEex_WriteDword(effectData + 0x110, 1)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local checkID = targetID
	local newEffectTarget = targetID
	local hasProtection = false
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local protectionType = IEex_ReadDword(effectData + 0x1C)
	local invert = false
	if (protectionType > 0 and protectionType <= 62 and bit.band(protectionType, 0x1) == 0) or (((protectionType > 63 and protectionType <= 73) or protectionType > 77) and bit.band(protectionType, 0x1) > 0) then
		invert = true
		protectionType = protectionType - 1
	end
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if bit.band(savingthrow, 0x20000) > 0 and IEex_IsSprite(sourceID, true) then
		checkID = sourceID
	end
	if bit.band(savingthrow, 0x200000) > 0 then
		newEffectTarget = sourceID
	end
	local checkData = IEex_GetActorShare(checkID)
	local sourceData = IEex_GetActorShare(sourceID)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local general = IEex_ReadByte(checkData + 0x25, 0x0)
	local race = IEex_ReadByte(checkData + 0x26, 0x0)
	local specifics = IEex_ReadByte(checkData + 0x33, 0x0)
	local gender = IEex_ReadByte(checkData + 0x34, 0x0)
	local alignment = IEex_ReadByte(checkData + 0x35, 0x0)
	local animation = IEex_ReadDword(checkData + 0x5C4)
	local subrace = IEex_ReadByte(checkData + 0x7FF, 0x0)
	local stateValue = bit.bor(IEex_ReadDword(checkData + 0x5BC), IEex_ReadDword(checkData + 0x920))
	if protectionType == 0 then
		hasProtection = true
	elseif protectionType == 1 and general == 4 then
		hasProtection = true
	elseif protectionType == 3 then
		local baseFireResistance = IEex_ReadByte(checkData + 0x5F1, 0x0)
		if animation == 29456 or animation == 57896 or animation == 60376 or ((animation == 32517 or animation == 32518 or animation == 59176 or animation == 60507 or animation == 62216) and baseFireResistance >= 50) then
			hasProtection = true
		end
	elseif protectionType == 5 and general == 1 then
		hasProtection = true
	elseif protectionType == 7 and general == 2 then
		hasProtection = true
	elseif protectionType == 9 and (race == 152 or race == 161) then
		hasProtection = true
	elseif protectionType == 11 then
		if animation == 60313 or animation == 60329 or animation == 60337 then
			hasProtection = true
		end
	elseif protectionType == 13 then
		if parameter1 == 0 then
			parameter1 = 48
		end
		local animationData = IEex_ReadDword(checkData + 0x50F0)
		if animationData > 0 and IEex_ReadDword(animationData + 0x10) >= parameter1 then
			hasProtection = true
		end
	elseif protectionType == 15 and (race == 2 or race == 183) then
		hasProtection = true
	elseif protectionType == 17 then
		if animation == 59225 or animation == 59385 then
			hasProtection = true
		end
	elseif protectionType == 19 and race == 3 then
		hasProtection = true
	elseif protectionType == 21 and (general == 1 or general == 2) then
		hasProtection = true
	elseif protectionType == 23 then
		if bit.band(stateValue, 0x40000) > 0 then
			hasProtection = true
		end
	elseif protectionType == 25 then
		local baseColdResistance = IEex_ReadByte(checkData + 0x5F2, 0x0)
		if animation == 29187 or animation == 31491 or animation == 57656 or animation == 58201 or animation == 58664 or animation == 59192 or animation == 59244 or animation == 59337 or animation == 60184 or animation == 60392 or animation == 60427 or ((animation == 4097 or animation == 59176) and baseColdResistance >= 50) then
			hasProtection = true
		end
	elseif protectionType == 27 and (race == ex_construct_race or specifics == 115) then
		hasProtection = true
	elseif protectionType == 29 then
		if animation == 59144 then
			hasProtection = true
		end
	elseif protectionType == 31 then
		if animation == 60313 or animation == 60329 or animation == 60337 or general == 4 then
			hasProtection = true
		end
	elseif protectionType == 33 and bit.band(alignment, 0x3) == 0x1 then
		hasProtection = true
	elseif protectionType == 35 and bit.band(alignment, 0x3) == 0x2 then
		hasProtection = true
	elseif protectionType == 37 and bit.band(alignment, 0x3) == 0x3 then
		hasProtection = true
	elseif protectionType == 39 and IEex_GetActorStat(targetID, 102) > 0 then
		hasProtection = true
	elseif protectionType == 41 and IEex_IsSprite(sourceID, true) then
		local targetAlignment = IEex_ReadByte(creatureData + 0x35, 0x0)
		local sourceAlignment = IEex_ReadByte(sourceData + 0x35, 0x0)
		if bit.band(targetAlignment, 0x3) == bit.band(sourceAlignment, 0x3) then
			hasProtection = true
		end
	elseif protectionType == 43 and targetID == sourceID then
		hasProtection = true
	elseif protectionType == 45 then
		if animation == 58280 or animation == 57912 or animation == 57938 or animation == 58008 or animation == 59368 or animation == 59385 or animation == 62475 or animation == 62491 then
			hasProtection = true
		end
	elseif protectionType == 47 then
		if general == 4 or race == ex_construct_race or specifics == 115 then
			hasProtection = true
		end
	elseif protectionType == 49 and IEex_IsSprite(sourceID, true) then
		if IEex_CompareActorAllegiances(targetID, sourceID) == 1 then
			hasProtection = true
		end
	elseif protectionType == 51 and IEex_IsSprite(sourceID, true) then
		if IEex_CompareActorAllegiances(targetID, sourceID) == -1 then
			hasProtection = true
		end
	elseif protectionType == 53 then
		local baseFireResistance = IEex_ReadByte(checkData + 0x5F1, 0x0)
		local baseColdResistance = IEex_ReadByte(checkData + 0x5F2, 0x0)
		if animation == 29456 or animation == 57896 or animation == 60376 or ((animation == 32517 or animation == 32518 or animation == 59176 or animation == 60507 or animation == 62216) and baseFireResistance >= 50) or animation == 29187 or animation == 31491 or animation == 57656 or animation == 58201 or animation == 58664 or animation == 59192 or animation == 59244 or animation == 59337 or animation == 60184 or animation == 60392 or animation == 60427 or ((animation == 4097 or animation == 59176) and baseColdResistance >= 50) then
			hasProtection = true
		end
	elseif protectionType == 55 then
		if general == 4 or race == ex_construct_race or specifics == 115 or race == ex_fiend_race or race == 152 or race == 161 or race == 210 or race == 190 then
			hasProtection = true
		end
	elseif protectionType == 57 and gender == 1 then
		hasProtection = true
	elseif protectionType == 59 and bit.band(alignment, 0x30) == 0x10 then
		hasProtection = true
	elseif protectionType == 61 and bit.band(alignment, 0x30) == 0x30 then
		hasProtection = true
	elseif protectionType == 64 then
		if animation == 59400 or animation == 59416 or animation == 59426 or animation == 59448 or animation == 59458 or animation == 59481 or animation == 59496 or animation == 59512 or animation == 59528 or animation == 59609 or animation == 59641 then
			hasProtection = true
		end
	elseif protectionType == 66 and IEex_GetActorSpellState(checkID, 38) then
		hasProtection = true
	elseif protectionType == 68 then
		if bit.band(stateValue, 0x10000000) > 0 then
			hasProtection = true
		end
	elseif protectionType == 70 then
		if animation == 32513 or animation == 61427 then
			hasProtection = true
		end
	elseif protectionType == 72 then
		if bit.band(stateValue, 0x1000) > 0 then
			hasProtection = true
		end
	elseif protectionType == 82 then
		if race == 183 or (race == 2 and subrace == 1) then
			hasProtection = true
		end
	elseif protectionType == 84 then
		if race == 185 or (race == 4 and subrace == 2) then
			hasProtection = true
		end
	elseif protectionType == 88 then
		local areaData = IEex_ReadDword(checkData + 0x12)
		if areaData > 0 and bit.band(IEex_ReadWord(areaData + 0x40, 0x0), 0x1) > 0 then
			hasProtection = true
		end
	elseif protectionType == 90 then
		if animation == 61264 or animation == 61280 or animation == 61296 then
			hasProtection = true
		end
	elseif protectionType == 92 then
		if race == ex_fiend_race or race == 152 or race == 161 or race == 210 then
			hasProtection = true
		end
	elseif protectionType == 94 then
		if general == 4 or race == ex_construct_race or specifics == 115 or race == 190 then
			hasProtection = true
		end
	elseif protectionType == 96 then
		if general == 4 or race == ex_construct_race or specifics == 115 or animation == 29442 or (animation >= 30976 and animation <= 30979) or race == 190 then
			hasProtection = true
		end
	elseif protectionType == 98 then
		if race == 183 or (race == 2 and subrace == 1) or race == 185 or (race == 4 and subrace == 2) then
			hasProtection = true
		end
	elseif protectionType == 100 then
		if race == 183 or (race == 2 and subrace == 1) or race == 185 or (race == 4 and subrace == 2) or animation == 58153 or animation == 58201 or animation == 58217 or animation == 59656 or animation == 59672 or animation == 60313 or animation == 60329 or animation == 60337 then
			hasProtection = true
		end
	elseif protectionType == 102 then
		if race == ex_fiend_race then
			hasProtection = true
		end
	elseif protectionType == 104 then
		if race == ex_fiend_race or general == 4 then
			hasProtection = true
		end
	elseif protectionType == 106 then
		if parameter1 == 0 then
			parameter1 = 50
		end
		if IEex_ReadSignedWord(checkData + 0x720, 0x0) >= parameter1 or IEex_GetActorSpellState(checkID, 184) then
			hasProtection = true
		end
	elseif protectionType == 108 then
		if IEex_GetActorSpellState(checkID, 182) or IEex_GetActorSpellState(checkID, 189) then
			hasProtection = true
		end
	elseif protectionType == 110 then
		if race == 168 and animation ~= 59545 and animation ~= 61961 and animation ~= 61976 then
			hasProtection = true
		end
	elseif protectionType == 112 then
		if general == 1 or general == 5 then
			hasProtection = true
		end
	elseif protectionType == 114 then
		if general == 4 or race == ex_construct_race or specifics == 115 or (race == ex_fiend_race and alignment == 0x33) then
			hasProtection = true
		end
	elseif protectionType == 116 then
		if IEex_GetItemSlotRES(checkID, 44 + IEex_ReadByte(checkData + 0x4C68, 0x0) * 2) ~= "" then
			hasProtection = true
		end
	elseif protectionType == 118 then
		if race == ex_construct_race or race == 190 or specifics == 115 then
			hasProtection = true
		end
	elseif protectionType == 120 and IEex_IsSprite(sourceID, true) then
		if IEex_CompareActorAllegiances(targetID, sourceID) == 1 and general ~= 4 then
			hasProtection = true
		end
	elseif protectionType == 122 and IEex_IsSprite(sourceID, true) then
		if IEex_CompareActorAllegiances(targetID, sourceID) == -1 and general ~= 4 then
			hasProtection = true
		end
	elseif protectionType == 124 and IEex_IsSprite(sourceID, true) then
		if IEex_CompareActorAllegiances(targetID, sourceID) == 1 and general == 4 then
			hasProtection = true
		end
	elseif protectionType == 126 and IEex_IsSprite(sourceID, true) then
		if IEex_CompareActorAllegiances(targetID, sourceID) == -1 and general == 4 then
			hasProtection = true
		end
	elseif protectionType == 128 and IEex_IsSprite(sourceID, true) then
		if parameter1 == 0 then
			parameter1 = 100
		end
		local animationData = IEex_ReadDword(checkData + 0x50F0)
		local sourceAnimationData = IEex_ReadDword(sourceData + 0x50F0)
		if animationData > 0 and sourceAnimationData > 0 and IEex_ReadDword(animationData + 0x10) > math.floor(IEex_ReadDword(sourceAnimationData + 0x10) * parameter1 / 100) then
			hasProtection = true
		end
	end

	if (hasProtection == true and invert == false) or (hasProtection == false and invert == true) then
		if bit.band(savingthrow, 0x10000) == 0 then
			if protectionType ~= 116 then
				IEex_ApplyEffectToActor(newEffectTarget, {
["opcode"] = 290,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
			else
				IEex_ApplyEffectToActor(newEffectTarget, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = ex_tra_55382,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(newEffectTarget, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
			end
		else
			IEex_ApplyEffectToActor(newEffectTarget, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
		end
	end
end

function MESPLAP2(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	IEex_WriteDword(effectData + 0x110, 1)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local checkID = targetID
	local newEffectTarget = targetID
	local doApply = false
	local parameter1 = IEex_ReadWord(effectData + 0x46, 0x0)
	local protectionType = IEex_ReadWord(effectData + 0x44, 0x0)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local invert = false
	if (protectionType > 0 and protectionType <= 62 and bit.band(protectionType, 0x1) == 0) or (((protectionType > 63 and protectionType <= 73) or (protectionType > 77)) and bit.band(protectionType, 0x1) > 0) then
		invert = true
		protectionType = protectionType - 1
	end
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if bit.band(savingthrow, 0x20000) > 0 and IEex_IsSprite(sourceID, true) then
		checkID = sourceID
	end
	if bit.band(savingthrow, 0x200000) > 0 then
		newEffectTarget = sourceID
	end
	local checkData = IEex_GetActorShare(checkID)
	local sourceData = IEex_GetActorShare(sourceID)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local general = IEex_ReadByte(checkData + 0x25, 0x0)
	local race = IEex_ReadByte(checkData + 0x26, 0x0)
	local specifics = IEex_ReadByte(checkData + 0x33, 0x0)
	local gender = IEex_ReadByte(checkData + 0x34, 0x0)
	local alignment = IEex_ReadByte(checkData + 0x35, 0x0)
	local animation = IEex_ReadDword(checkData + 0x5C4)
	local subrace = IEex_ReadByte(checkData + 0x7FF, 0x0)
	local stateValue = bit.bor(IEex_ReadDword(checkData + 0x5BC), IEex_ReadDword(checkData + 0x920))
	if protectionType == 0 then
		doApply = true
	elseif protectionType == 1 and general == 4 then
		doApply = true
	elseif protectionType == 3 then
		local baseFireResistance = IEex_ReadByte(checkData + 0x5F1, 0x0)
		if animation == 29456 or animation == 57896 or animation == 60376 or ((animation == 32517 or animation == 32518 or animation == 59176 or animation == 60507 or animation == 62216) and baseFireResistance >= 50) then
			doApply = true
		end
	elseif protectionType == 5 and general == 1 then
		doApply = true
	elseif protectionType == 7 and general == 2 then
		doApply = true
	elseif protectionType == 9 and (race == 152 or race == 161) then
		doApply = true
	elseif protectionType == 11 then
		if animation == 60313 or animation == 60329 or animation == 60337 then
			doApply = true
		end
	elseif protectionType == 13 then
		if parameter1 == 0 then
			parameter1 = 48
		end
		local animationData = IEex_ReadDword(checkData + 0x50F0)
		if animationData > 0 and IEex_ReadDword(animationData + 0x10) >= parameter1 then
			hasProtection = true
		end
	elseif protectionType == 15 and (race == 2 or race == 183) then
		doApply = true
	elseif protectionType == 17 then
		if animation == 59225 or animation == 59385 then
			doApply = true
		end
	elseif protectionType == 19 and race == 3 then
		doApply = true
	elseif protectionType == 21 and (general == 1 or general == 2) then
		doApply = true
	elseif protectionType == 23 then
		if bit.band(stateValue, 0x40000) > 0 then
			doApply = true
		end
	elseif protectionType == 25 then
		local baseColdResistance = IEex_ReadByte(checkData + 0x5F2, 0x0)
		if animation == 29187 or animation == 31491 or animation == 57656 or animation == 58201 or animation == 58664 or animation == 59192 or animation == 59244 or animation == 59337 or animation == 60184 or animation == 60392 or animation == 60427 or ((animation == 4097 or animation == 59176) and baseColdResistance >= 50) then
			doApply = true
		end
	elseif protectionType == 27 and (race == ex_construct_race or specifics == 115) then
		doApply = true
	elseif protectionType == 29 then
		if animation == 59144 then
			doApply = true
		end
	elseif protectionType == 31 then
		if animation == 60313 or animation == 60329 or animation == 60337 or general == 4 then
			doApply = true
		end
	elseif protectionType == 33 and bit.band(alignment, 0x3) == 0x1 then
		doApply = true
	elseif protectionType == 35 and bit.band(alignment, 0x3) == 0x2 then
		doApply = true
	elseif protectionType == 37 and bit.band(alignment, 0x3) == 0x3 then
		doApply = true
	elseif protectionType == 39 and IEex_GetActorStat(targetID, 102) > 0 then
		doApply = true
	elseif protectionType == 41 and IEex_IsSprite(sourceID, true) then
		local targetAlignment = IEex_ReadByte(creatureData + 0x35, 0x0)
		local sourceAlignment = IEex_ReadByte(sourceData + 0x35, 0x0)
		if bit.band(targetAlignment, 0x3) == bit.band(sourceAlignment, 0x3) then
			doApply = true
		end
	elseif protectionType == 43 and targetID == sourceID then
		doApply = true
	elseif protectionType == 45 then
		if animation == 58280 or animation == 57912 or animation == 57938 or animation == 58008 or animation == 59368 or animation == 59385 or animation == 62475 or animation == 62491 then
			doApply = true
		end
	elseif protectionType == 47 then
		if general == 4 or race == ex_construct_race or specifics == 115 then
			doApply = true
		end
	elseif protectionType == 49 and IEex_IsSprite(sourceID, true) then
		if IEex_CompareActorAllegiances(targetID, sourceID) == 1 then
			doApply = true
		end
	elseif protectionType == 51 and IEex_IsSprite(sourceID, true) then
		if IEex_CompareActorAllegiances(targetID, sourceID) == -1 then
			doApply = true
		end
	elseif protectionType == 53 then
		local baseFireResistance = IEex_ReadByte(checkData + 0x5F1, 0x0)
		local baseColdResistance = IEex_ReadByte(checkData + 0x5F2, 0x0)
		if animation == 29456 or animation == 57896 or animation == 60376 or ((animation == 32517 or animation == 32518 or animation == 59176 or animation == 60507 or animation == 62216) and baseFireResistance >= 50) or animation == 29187 or animation == 31491 or animation == 57656 or animation == 58201 or animation == 58664 or animation == 59192 or animation == 59244 or animation == 59337 or animation == 60184 or animation == 60392 or animation == 60427 or ((animation == 4097 or animation == 59176) and baseColdResistance >= 50) then
			doApply = true
		end
	elseif protectionType == 55 then
		if general == 4 or race == ex_construct_race or specifics == 115 or race == ex_fiend_race or race == 152 or race == 161 or race == 210 or race == 190 then
			doApply = true
		end
	elseif protectionType == 57 and gender == 1 then
		doApply = true
	elseif protectionType == 59 and bit.band(alignment, 0x30) == 0x10 then
		doApply = true
	elseif protectionType == 61 and bit.band(alignment, 0x30) == 0x30 then
		doApply = true
	elseif protectionType == 64 then
		if animation == 59400 or animation == 59416 or animation == 59426 or animation == 59448 or animation == 59458 or animation == 59481 or animation == 59496 or animation == 59512 or animation == 59528 or animation == 59609 or animation == 59641 then
			doApply = true
		end
	elseif protectionType == 66 and IEex_GetActorSpellState(checkID, 38) then
		doApply = true
	elseif protectionType == 68 then
		if bit.band(stateValue, 0x10000000) > 0 then
			doApply = true
		end
	elseif protectionType == 70 then
		if animation == 32513 or animation == 61427 then
			doApply = true
		end
	elseif protectionType == 72 then
		if bit.band(stateValue, 0x1000) > 0 then
			doApply = true
		end
	elseif protectionType == 82 then
		if race == 183 or (race == 2 and subrace == 1) then
			doApply = true
		end
	elseif protectionType == 84 then
		if race == 185 or (race == 4 and subrace == 2) then
			doApply = true
		end
	elseif protectionType == 88 then
		local areaData = IEex_ReadDword(checkData + 0x12)
		if areaData > 0 and bit.band(IEex_ReadWord(areaData + 0x40, 0x0), 0x1) > 0 then
			doApply = true
		end
	elseif protectionType == 90 then
		if animation == 61264 or animation == 61280 or animation == 61296 then
			doApply = true
		end
	elseif protectionType == 92 then
		if race == ex_fiend_race or race == 152 or race == 161 or race == 210 then
			doApply = true
		end
	elseif protectionType == 94 then
		if general == 4 or race == ex_construct_race or specifics == 115 or race == 190 then
			doApply = true
		end
	elseif protectionType == 96 then
		if general == 4 or race == ex_construct_race or specifics == 115 or animation == 29442 or (animation >= 30976 and animation <= 30979) or race == 190 then
			doApply = true
		end
	elseif protectionType == 98 then
		if race == 183 or (race == 2 and subrace == 1) or race == 185 or (race == 4 and subrace == 2) then
			doApply = true
		end
	elseif protectionType == 100 then
		if race == 183 or (race == 2 and subrace == 1) or race == 185 or (race == 4 and subrace == 2) or animation == 58153 or animation == 58201 or animation == 58217 or animation == 59656 or animation == 59672 or animation == 60313 or animation == 60329 or animation == 60337 then
			doApply = true
		end
	elseif protectionType == 102 then
		if race == ex_fiend_race then
			doApply = true
		end
	elseif protectionType == 104 then
		if race == ex_fiend_race or general == 4 then
			doApply = true
		end
	elseif protectionType == 106 then
		if parameter1 == 0 then
			parameter1 = 50
		end
		if IEex_ReadSignedWord(checkData + 0x720, 0x0) >= parameter1 or IEex_GetActorSpellState(checkID, 184) then
			doApply = true
		end
	elseif protectionType == 108 then
		if IEex_GetActorSpellState(checkID, 182) or IEex_GetActorSpellState(checkID, 189) then
			doApply = true
		end
	elseif protectionType == 110 then
		if race == 168 and animation ~= 59545 and animation ~= 61961 and animation ~= 61976 then
			doApply = true
		end
	elseif protectionType == 112 then
		if general == 1 or general == 5 then
			doApply = true
		end
	elseif protectionType == 114 then
		if general == 4 or race == ex_construct_race or specifics == 115 or (race == ex_fiend_race and alignment == 0x33) then
			doApply = true
		end
	elseif protectionType == 116 then
		if IEex_GetItemSlotRES(checkID, 44 + IEex_ReadByte(checkData + 0x4C68, 0x0) * 2) ~= "" then
			doApply = true
		end
	elseif protectionType == 118 then
		if race == ex_construct_race or specifics == 115 or race == 190 then
			doApply = true
		end
	elseif protectionType == 120 and IEex_IsSprite(sourceID, true) then
		if IEex_CompareActorAllegiances(targetID, sourceID) == 1 and general ~= 4 then
			doApply = true
		end
	elseif protectionType == 122 and IEex_IsSprite(sourceID, true) then
		if IEex_CompareActorAllegiances(targetID, sourceID) == -1 and general ~= 4 then
			doApply = true
		end
	elseif protectionType == 124 and IEex_IsSprite(sourceID, true) then
		if IEex_CompareActorAllegiances(targetID, sourceID) == 1 and general == 4 then
			doApply = true
		end
	elseif protectionType == 126 and IEex_IsSprite(sourceID, true) then
		if IEex_CompareActorAllegiances(targetID, sourceID) == -1 and general == 4 then
			doApply = true
		end
	elseif protectionType == 128 and IEex_IsSprite(sourceID, true) then
		if parameter1 == 0 then
			parameter1 = 100
		end
		local animationData = IEex_ReadDword(checkData + 0x50F0)
		local sourceAnimationData = IEex_ReadDword(sourceData + 0x50F0)
		if animationData > 0 and sourceAnimationData > 0 and IEex_ReadDword(animationData + 0x10) > math.floor(IEex_ReadDword(sourceAnimationData + 0x10) * parameter1 / 100) then
			hasProtection = true
		end
	end

	if (doApply == true and invert == false) or (doApply == false and invert == true) then
		IEex_ApplyEffectToActor(newEffectTarget, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["duration"] = 0,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["target_x"] = IEex_ReadDword(effectData + 0x84),
["target_y"] = IEex_ReadDword(effectData + 0x88),
["source_id"] = sourceID,
})
	end
end

function MEPSTACK(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	if targetID <= 0 or not IEex_IsSprite(sourceID, true) then return end
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local school = IEex_ReadDword(effectData + 0x48)
	local sourceSpell = IEex_ReadLString(effectData + 0x18, 8)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	if sourceSpell == "" then
		sourceSpell = parent_resource
	end
	IEex_IterateActorEffects(targetID, function(eData)
		local thesourceID = IEex_ReadDword(eData + 0x110)
		local theschool = IEex_ReadDword(eData + 0x4C)
		local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
		if (thesourceID == sourceID or (thesourceID <= 0 and bit.band(savingthrow, 0x10000) > 0)) and (((theparent_resource == sourceSpell) and bit.band(savingthrow, 0x20000) == 0) or ((theschool == school) and bit.band(savingthrow, 0x20000) > 0)) then
			IEex_WriteDword(eData + 0x28, 0)
			IEex_WriteDword(eData + 0x114, 1)
		end
	end)
end

function MEREMOPC(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local match_opcode = IEex_ReadSignedWord(effectData + 0x18, 0x0)
	local match_opcode2 = IEex_ReadSignedWord(effectData + 0x1A, 0x0)
	local match_parameter2 = IEex_ReadDword(effectData + 0x1C)
	local match_special = IEex_ReadDword(effectData + 0x44)
	local match_resource = IEex_ReadLString(effectData + 0x18, 8)
	local checkResource = (bit.band(IEex_ReadDword(effectData + 0x3C), 0x10000) > 0)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	if targetID <= 0x0 then return end
	IEex_IterateActorEffects(targetID, function(eData)
		local the_opcode = IEex_ReadDword(eData + 0x10)
		local the_parameter2 = IEex_ReadDword(eData + 0x20)
		local the_special = IEex_ReadDword(eData + 0x48)
		local the_resource = IEex_ReadLString(eData + 0x30, 8)
		if not checkResource then
			if (match_opcode == -1 or match_opcode == the_opcode or (match_opcode2 > 0 and match_opcode2 == the_opcode)) and (match_parameter2 == -1 or match_parameter2 == the_parameter2) and (match_special == -1 or match_special == the_special) then
				IEex_WriteDword(eData + 0x28, IEex_ReadDword(eData + 0x6C))
			end
		else
			if (match_special == -1 or match_special == the_opcode) and match_resource == the_resource then
				IEex_WriteDword(eData + 0x28, IEex_ReadDword(eData + 0x6C))
			end
		end
	end)
end

function MEREMSSE(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local match_opcode = IEex_ReadDword(effectData + 0x18, 0x0)
	local match_parameter2 = IEex_ReadDword(effectData + 0x1C)
	local match_special = IEex_ReadDword(effectData + 0x44)
	local match_resource = IEex_ReadLString(effectData + 0x18, 8)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	if targetID <= 0x0 then return end
	local resourcesToRemove = {}
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thespecial = IEex_ReadDword(eData + 0x48)
		if (match_opcode == -1 or match_opcode == theopcode) and (match_parameter2 == -1 or match_parameter2 == theparameter2) and (match_special == -1 or match_special == thespecial) then
			table.insert(resourcesToRemove, IEex_ReadLString(eData + 0x94, 8))
		end
	end)
	for k, res in ipairs(resourcesToRemove) do
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["resource"] = res,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
	end
end

function MEMARKCR(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - time_applied) / 15)
	end
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter4"] = IEex_ReadDword(creatureData + 0x700),
["savingthrow"] = 0x200000,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
end

function MEAOESP2(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 0x1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local maxradius = IEex_ReadWord(effectData + 0x44, 0x0)
	local minradius = IEex_ReadSignedWord(effectData + 0x46, 0x0)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local sourceX = IEex_ReadDword(effectData + 0x7C)
	local sourceY = IEex_ReadDword(effectData + 0x80)
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	if bit.band(savingthrow, 0x40000) > 0 then
		sourceID = targetID
	end
	if (targetX <= 0 and targetY <= 0) or bit.band(savingthrow, 0x80000) > 0 then
		targetX = IEex_ReadDword(creatureData + 0x6)
		targetY = IEex_ReadDword(creatureData + 0xA)
	end
	local ids = {}
	if IEex_ReadDword(creatureData + 0x12) > 0 then
		ids = IEex_GetIDArea(sourceID, 0x31)
	end
	local closestDistance = 0x7FFFFFFF
	local possibleTargets = {}
	if bit.band(savingthrow, 0x40000000) == 0 then
		for k, currentID in ipairs(ids) do
			local currentShare = IEex_GetActorShare(currentID)
			if currentShare > 0 then
				local currentX = IEex_ReadDword(currentShare + 0x6)
				local currentY = IEex_ReadDword(currentShare + 0xA)
				local currentDistance = IEex_GetDistanceIsometric(targetX, targetY, currentX, currentY)
				local states = IEex_ReadDword(currentShare + 0x5BC)
				local animation = IEex_ReadDword(currentShare + 0x5C4)
				local cea = IEex_CompareActorAllegiances(sourceID, currentID)
				if currentDistance < maxradius and currentDistance >= minradius and (bit.band(savingthrow, 0x2000000) == 0 or currentDistance < closestDistance) and (bit.band(savingthrow, 0x8000) == 0 or bit.band(IEex_ReadByte(currentShare + 0x35, 0x0), 0x3) == 0x3) and (bit.band(savingthrow, 0x200000) == 0 or cea ~= 1) and (bit.band(savingthrow, 0x400000) == 0 or cea ~= 0) and (bit.band(savingthrow, 0x800000) == 0 or cea ~= -1) and (bit.band(savingthrow, 0x1000000) == 0 or currentID ~= targetID) and (bit.band(savingthrow, 0x4000000) == 0 or IEex_CheckActorLOSObject(sourceID, currentID)) and animation >= 0x1000 and (animation < 0xD000 or animation >= 0xE000) and bit.band(states, 0x800) == 0 and IEex_ReadByte(currentShare + 0x838, 0x0) == 0 then
					if bit.band(savingthrow, 0x2000000) == 0 then
						table.insert(possibleTargets, {currentID, currentX, currentY})
					else
						closestDistance = currentDistance
						possibleTargets = {{currentID, currentX, currentY}}
					end
				end
			end
		end
	end
	if #possibleTargets > 0 then
		if bit.band(savingthrow, 0x10000) == 0 then
			local randomTarget = possibleTargets[math.random(#possibleTargets)]
			IEex_ApplyEffectToActor(randomTarget[1], {
["opcode"] = 402,
["target"] = 2,
["timing"] = 9,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["internal_flags"] = internalFlags,
["casterlvl"] = casterlvl,
["source_target"] = randomTarget[1],
["source_id"] = sourceID,
["source_x"] = sourceX,
["source_y"] = sourceY,
--["target_x"] = randomTarget[2],
--["target_y"] = randomTarget[3]
["target_x"] = targetX,
["target_y"] = targetY
})
		else
			if bit.band(savingthrow, 0x8000000) == 0 then
				for k, currentTarget in ipairs(possibleTargets) do
					IEex_ApplyEffectToActor(currentTarget[1], {
["opcode"] = 402,
["target"] = 2,
["timing"] = 9,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["internal_flags"] = internalFlags,
["casterlvl"] = casterlvl,
["source_target"] = currentTarget[1],
["source_id"] = sourceID,
["source_x"] = sourceX,
["source_y"] = sourceY,
--["target_x"] = randomTarget[2],
--["target_y"] = randomTarget[3]
["target_x"] = targetX,
["target_y"] = targetY
})
				end
			else
				for i = 1, #possibleTargets, 1 do
					IEex_ApplyEffectToActor(possibleTargets[i][1], {
["opcode"] = 402,
["target"] = 2,
["timing"] = 6,
["duration"] = IEex_GetGameTick() + i,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["internal_flags"] = internalFlags,
["casterlvl"] = casterlvl,
["source_target"] = possibleTargets[i][1],
["source_id"] = sourceID,
["source_x"] = sourceX,
["source_y"] = sourceY,
--["target_x"] = randomTarget[2],
--["target_y"] = randomTarget[3]
["target_x"] = targetX,
["target_y"] = targetY
})
				end
			end
		end
	elseif bit.band(savingthrow, 0x20000) > 0 then
		local deltaX = math.random(maxradius * 2 + 1) - maxradius - 1
		local deltaY = math.random(maxradius * 2 + 1) - maxradius - 1
		local currentDistance = math.floor((deltaX ^ 2 + deltaY ^ 2) ^ .5)
		while currentDistance >= maxradius or currentDistance < minradius do
			deltaX = math.random(maxradius * 2 + 1) - maxradius - 1
			deltaY = math.random(maxradius * 2 + 1) - maxradius - 1
			currentDistance = math.floor((deltaX ^ 2 + deltaY ^ 2) ^ .5)
		end
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 148,
["target"] = 2,
["timing"] = 9,
["parameter1"] = IEex_ReadByte(effectData + 0xC4, 0x0),
["parameter2"] = 2,
["resource"] = spellRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID,
["source_x"] = sourceX,
["source_y"] = sourceY,
["target_x"] = targetX + deltaX,
["target_y"] = targetY + deltaY
})
	elseif bit.band(savingthrow, 0x2000) > 0 then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 41008,
["source_id"] = sourceID,
})
	elseif bit.band(savingthrow, 0x4000) > 0 then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 26518,
["source_id"] = sourceID,
})
	end
end

me_chain_lightning_index = 1
me_chain_lightning_list = {}
function MECHAIN2(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local casterLevel = IEex_ReadByte(effectData + 0xC4, 0x0)
	if not IEex_IsSprite(sourceID, true) then return end
	local maxradius = IEex_ReadWord(effectData + 0x44, 0x0)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local vvcresource = IEex_ReadLString(effectData + 0x6C)
	if #vvcresource <= 1 then
		vvcresource = "USCHAINL"
	end
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local special = IEex_ReadDword(effectData + 0x44)
	local parameter3 = IEex_ReadDword(effectData + 0x5C)
	local parameter4 = IEex_ReadDword(effectData + 0x60)
	local numCastings = IEex_ReadSignedWord(effectData + 0x46, 0x0)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if parameter3 == 0 then
		parameter3 = me_chain_lightning_index
		me_chain_lightning_index = me_chain_lightning_index + 1
		me_chain_lightning_list[parameter3] = {}
		if numCastings <= 0 then
			numCastings = casterLevel
		end
	else
		numCastings = parameter4
		if me_chain_lightning_index == 1 or numCastings <= 0 then return end
	end
	local chainSourceID = sourceID
	local listSize = #me_chain_lightning_list[parameter3]
	if listSize > 0 then
		chainSourceID = me_chain_lightning_list[parameter3][listSize]
	end
	table.insert(me_chain_lightning_list[parameter3], targetID)
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
	local ids = {}
	if IEex_ReadDword(creatureData + 0x12) > 0 then
		ids = IEex_GetIDArea(targetID, 0x31)
	end
	local closestID = 0
	local closestDistance = 0x7FFFFFFF
	for k, currentID in ipairs(ids) do
		local currentShare = IEex_GetActorShare(currentID)
		if currentShare > 0 then
			local currentX = IEex_ReadDword(currentShare + 0x6)
			local currentY = IEex_ReadDword(currentShare + 0xA)
			local currentDistance = IEex_GetDistanceIsometric(targetX, targetY, currentX, currentY)
			local states = IEex_ReadDword(currentShare + 0x5BC)
			local animation = IEex_ReadDword(currentShare + 0x5C4)
			local cea = IEex_CompareActorAllegiances(sourceID, currentID)
			if currentDistance < maxradius and (bit.band(savingthrow, 0x2000000) == 0 or currentDistance < closestDistance) and (bit.band(savingthrow, 0x8000) == 0 or bit.band(IEex_ReadByte(currentShare + 0x35, 0x0), 0x3) == 0x3) and (bit.band(savingthrow, 0x200000) == 0 or cea ~= 1) and (bit.band(savingthrow, 0x400000) == 0 or cea ~= 0) and (bit.band(savingthrow, 0x800000) == 0 or cea ~= -1) and (bit.band(savingthrow, 0x4000000) == 0 or IEex_CheckActorLOSObject(chainSourceID, currentID)) and animation >= 0x1000 and (animation < 0xD000 or animation >= 0xE000) and bit.band(states, 0x800) == 0 and IEex_ReadByte(currentShare + 0x838, 0x0) == 0 then
				local isNewTarget = true
				for k2, oldID in ipairs(me_chain_lightning_list[parameter3]) do
					if currentID == oldID then
						isNewTarget = false
					end
				end
				if bit.band(savingthrow, 0x1000000) > 0 and currentID ~= targetID then
					isNewTarget = true
				end
				if isNewTarget then
					closestID = currentID
					closestDistance = currentDistance
				end
			end
		end
	end
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local chainSourceData = IEex_GetActorShare(chainSourceID)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 430,
["target"] = 2,
["timing"] = 9,
["parameter2"] = 108,
["resource"] = vvcresource,
["parent_resource"] = vvcresource,
["target_x"] = targetX,
["target_y"] = targetY,
["source_target"] = targetID,
["source_id"] = chainSourceID
})
	if bit.band(savingthrow, 0x10000000) > 0 then
		casterLevel = casterLevel - 1
		IEex_WriteByte(effectData + 0xC4, casterLevel)
		casterlvl = IEex_ReadDword(effectData + 0xC4)
	end
	if bit.band(savingthrow, 0x20000000) > 0 then
		casterLevel = math.floor(casterLevel / 2)
		IEex_WriteByte(effectData + 0xC4, casterLevel)
		casterlvl = IEex_ReadDword(effectData + 0xC4)
	end
	if bit.band(savingthrow, 0x40000000) > 0 and #me_chain_lightning_list[parameter3] == 1 then
		casterLevel = math.floor(casterLevel / 2)
		IEex_WriteByte(effectData + 0xC4, casterLevel)
		casterlvl = IEex_ReadDword(effectData + 0xC4)
	end
	if closestID == 0 or casterLevel <= 1 then return end
	IEex_ApplyEffectToActor(closestID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parameter1"] = IEex_ReadDword(effectData + 0x18),
["parameter2"] = IEex_ReadDword(effectData + 0x1C),
["parameter3"] = parameter3,
["parameter4"] = numCastings - 1,
["savingthrow"] = savingthrow,
["resource"] = "MECHAIN2",
["vvcresource"] = vvcresource,
["parent_resource"] = parent_resource,
["internal_flags"] = internalFlags,
["special"] = special,
["casterlvl"] = casterlvl,
["source_target"] = closestID,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(closestID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 9,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["internal_flags"] = internalFlags,
["casterlvl"] = casterlvl,
["source_target"] = closestID,
["source_id"] = sourceID
})

end

local state_save_penalties = {
["USWI452"] = {0x4, 6},
["USWI452D"] = {0x4, 6},
}
function MESPLSAV(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceData = IEex_GetActorShare(sourceID)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local savebonus = IEex_ReadDword(effectData + 0x40)
	if bit.band(savingthrow, 0x8000000) > 0 then
		savebonus = savebonus * -1
	end
	local saveBonusStat = IEex_ReadByte(effectData + 0x44, 0x0)
	local bonusStatMultiplier = IEex_ReadByte(effectData + 0x45, 0x0)
	local bonusStatDivisor = IEex_ReadByte(effectData + 0x46, 0x0)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	local summonerID = IEex_GetActorSummonerID(sourceID)
	local newSourceID = sourceID
	if bit.band(savingthrow, 0x20000000) > 0 and IEex_IsSprite(summonerID, true) then
		casterlvl = bit.band(IEex_ReadDword(sourceData + 0x730), 0xFFFFFF)
		casterClass = IEex_ReadByte(sourceData + 0x731, 0x0)
		sourceID = summonerID
		sourceData = IEex_GetActorShare(sourceID)
		newSourceID = sourceID
	end
	if bit.band(savingthrow, 0x40000000) > 0 and IEex_IsSprite(summonerID, true) then
		casterlvl = bit.band(IEex_ReadDword(sourceData + 0x730), 0xFFFFFF)
		casterClass = IEex_ReadByte(sourceData + 0x731, 0x0)
		newSourceID = sourceID
		sourceID = summonerID
		sourceData = IEex_GetActorShare(sourceID)
		if casterClass == 11 then
			saveBonusStat = 38
		elseif casterClass == 3 or casterClass == 4 or casterClass == 7 or casterClass == 8 then
			saveBonusStat = 39
		elseif casterClass == 2 or casterClass == 10 then
			saveBonusStat = 42
		end
	end
	local sourceSpell = ex_source_spell[parent_resource]
	if sourceSpell == nil then
		sourceSpell = parent_resource
	end
	local classSpellLevel = 0
	if IEex_IsSprite(sourceID, true) then
		classSpellLevel = IEex_GetClassSpellLevel(sourceID, casterClass, sourceSpell)
	end
	if classSpellLevel <= 0 then
		local resWrapper = IEex_DemandRes(sourceSpell, "SPL")
		if resWrapper:isValid() then
			local spellData = resWrapper:getData()
			if IEex_ReadWord(spellData + 0x1C, 0x0) == 1 or IEex_ReadWord(spellData + 0x1C, 0x0) == 2 then
				classSpellLevel = IEex_ReadDword(spellData + 0x34)
			end
		end
		resWrapper:free()
	end
	savebonus = savebonus + classSpellLevel
	local trueschool = 0
	if ex_trueschool[sourceSpell] ~= nil then
		trueschool = ex_trueschool[sourceSpell]
	end
	if trueschool > 0 then
		local sourceKit = IEex_GetActorStat(sourceID, 89)
		if bit.band(sourceKit, 0x4000) > 0 then
			savebonus = savebonus + 1
		elseif ex_spell_focus_component_installed then
			if bit.band(savingthrow, 0x2000) == 0 then
				if trueschool == 1 and bit.band(sourceKit, 0x40) > 0 or trueschool == 2 and bit.band(sourceKit, 0x80) > 0 or trueschool == 3 and bit.band(sourceKit, 0x100) > 0 or trueschool == 5 and bit.band(sourceKit, 0x400) > 0 then
					savebonus = savebonus + 2
				elseif trueschool == 1 and bit.band(sourceKit, 0x2000) > 0 or trueschool == 2 and bit.band(sourceKit, 0x800) > 0 or trueschool == 3 and bit.band(sourceKit, 0x1000) > 0 or trueschool == 5 and bit.band(sourceKit, 0x200) > 0 then
					savebonus = savebonus - 2
				end
			else
				if trueschool == 1 and bit.band(sourceKit, 0x40) > 0 or trueschool == 2 and bit.band(sourceKit, 0x80) > 0 or trueschool == 3 and bit.band(sourceKit, 0x100) > 0 or trueschool == 4 and bit.band(sourceKit, 0x200) > 0 or trueschool == 5 and bit.band(sourceKit, 0x400) > 0 or trueschool == 6 and bit.band(sourceKit, 0x800) > 0 or trueschool == 7 and bit.band(sourceKit, 0x1000) > 0 or trueschool == 8 and bit.band(sourceKit, 0x2000) > 0 then
					savebonus = savebonus + 2
				end
			end
		end
	end
	if state_save_penalties[parent_resource] ~= nil then
		local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
		if bit.band(stateValue, state_save_penalties[parent_resource][1]) > 0 then
			savebonus = savebonus + state_save_penalties[parent_resource][2]
		end
	end
	local saveBonusStatValue = 0
	if IEex_IsSprite(sourceID, true) then
		local alignment = IEex_ReadByte(sourceData + 0x35, 0x0)
		if bit.band(alignment, 0x3) == 0x3 and IEex_GetActorSpellState(targetID, 1) then
			savebonus = savebonus - 2
		end
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if theopcode == 502 and theresource == "MESVVTYP" then
				if (theparameter2 == 2 and IEex_ReadByte(creatureData + 0x24, 0x0) == theparameter1) or (theparameter2 == 3 and IEex_ReadByte(creatureData + 0x25, 0x0) == theparameter1) or (theparameter2 == 4 and IEex_ReadByte(creatureData + 0x26, 0x0) == theparameter1) or (theparameter2 == 5 and bit.band(IEex_ReadDword(creatureData + 0x38), theparameter1) > 0) or (theparameter2 == 6 and IEex_ReadByte(creatureData + 0x27, 0x0) == theparameter1) or (theparameter2 == 7 and IEex_ReadByte(creatureData + 0x34, 0x0) == theparameter1) then
					savebonus = savebonus - thespecial
				elseif theparameter2 == 8 then
					if alignment == theparameter1 or bit.band(alignment, 0x3) == theparameter1 or bit.band(alignment, 0x30) == theparameter1 then
						savebonus = savebonus - thespecial
					end
				end
			end
		end)
		if bit.band(savingthrow, 0x40) > 0 then
			savebonus = savebonus + IEex_ReadByte(sourceData + 0x784, 0x0) * 2
		end
		if bit.band(savingthrow, 0x80) > 0 then
			savebonus = savebonus + IEex_ReadByte(sourceData + 0x785, 0x0) * 2
		end
		if bit.band(savingthrow, 0x100) > 0 then
			savebonus = savebonus + IEex_ReadByte(sourceData + 0x786, 0x0) * 2
		end
		if bit.band(savingthrow, 0x200) > 0 then
			savebonus = savebonus + IEex_ReadByte(sourceData + 0x787, 0x0) * 2
		end
		if bit.band(savingthrow, 0x40000) == 0 then
			if casterClass == 11 then
				savebonus = savebonus - math.floor((IEex_GetActorStat(newSourceID, 38) - 10) / 2)
			elseif casterClass == 3 or casterClass == 4 or casterClass == 7 or casterClass == 8 then
				savebonus = savebonus - math.floor((IEex_GetActorStat(newSourceID, 39) - 10) / 2)
			elseif casterClass == 2 or casterClass == 10 then
				savebonus = savebonus - math.floor((IEex_GetActorStat(newSourceID, 42) - 10) / 2)
			end
		end
		if saveBonusStat > 0 then
			if (saveBonusStat == 120 or saveBonusStat == 160) and casterClass == 0 then
				local highestStatValue = IEex_GetActorStat(sourceID, 38)
				saveBonusStat = 38
				if IEex_GetActorStat(sourceID, 39) > highestStatValue then
					highestStatValue = IEex_GetActorStat(sourceID, 39)
					saveBonusStat = 39
				end
				if IEex_GetActorStat(sourceID, 42) > highestStatValue then
					highestStatValue = IEex_GetActorStat(sourceID, 42)
					saveBonusStat = 42
				end
				saveBonusStatValue = IEex_GetActorStat(sourceID, saveBonusStat)
			elseif saveBonusStat ~= 120 and saveBonusStat ~= 160 then
				saveBonusStatValue = IEex_GetActorStat(sourceID, saveBonusStat)
			end
			if saveBonusStat >= 36 and saveBonusStat <= 42 then
				saveBonusStatValue = math.floor((saveBonusStatValue - 10) / 2)
			end
			if bonusStatMultiplier ~= 0 then
				saveBonusStatValue = saveBonusStatValue * bonusStatMultiplier
			end
			if bonusStatDivisor ~= 0 then
				saveBonusStatValue = math.floor(saveBonusStatValue / bonusStatDivisor)
			end
			savebonus = savebonus + saveBonusStatValue
		end
	end
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 288 and theparameter2 == 236 and bit.band(thesavingthrow, 0x10000) == 0 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if (bit.band(thesavingthrow, 0x40000) == 0 or IEex_CompareActorAllegiances(sourceID, targetID) == 1) and (bit.band(thesavingthrow, 0x100000) == 0 or casterDomain == 0) then
				if (theresource == "" or theresource == sourceSpell) and (thespecial == trueschool or thespecial <= 0 or ((thespecial == 4 or thespecial == 5) and bit.band(savingthrow, 0x40) > 0) or ((thespecial == 2 or thespecial == 6) and bit.band(savingthrow, 0x80) > 0) or ((thespecial == 3 or thespecial == 7) and bit.band(savingthrow, 0x100) > 0) or ((thespecial == 1 or thespecial == 8) and bit.band(savingthrow, 0x200) > 0)) then
					savebonus = savebonus + theparameter1
				end
			end
		end
	end)
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 288 and theparameter2 == 236 and bit.band(thesavingthrow, 0x10000) > 0 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if (bit.band(thesavingthrow, 0x40000) == 0 or IEex_CompareActorAllegiances(sourceID, targetID) == 1) and (bit.band(thesavingthrow, 0x100000) == 0 or casterDomain == 0) then
				if (theresource == "" or theresource == sourceSpell) and (thespecial == trueschool or thespecial <= 0 or ((thespecial == 4 or thespecial == 5) and bit.band(savingthrow, 0x40) > 0) or ((thespecial == 2 or thespecial == 6) and bit.band(savingthrow, 0x80) > 0) or ((thespecial == 3 or thespecial == 7) and bit.band(savingthrow, 0x100) > 0) or ((thespecial == 1 or thespecial == 8) and bit.band(savingthrow, 0x200) > 0)) then
					savebonus = savebonus + theparameter1
				end
			end
		end
	end)
	local newSavingThrow = 0
	if bit.band(savingthrow, 0x400) > 0 then
		newSavingThrow = bit.bor(newSavingThrow, 0x4)
	end
	if bit.band(savingthrow, 0x800) > 0 then
		newSavingThrow = bit.bor(newSavingThrow, 0x8)
	end
	if bit.band(savingthrow, 0x1000) > 0 then
		newSavingThrow = bit.bor(newSavingThrow, 0x10)
	end

	if bit.band(savingthrow, 0x10000000) > 0 then
		parent_resource = spellRES
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["savingthrow"] = newSavingThrow,
["savebonus"] = savebonus,
["casterlvl"] = casterlvl,
["resource"] = spellRES,
["parent_resource"] = parent_resource,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_target"] = targetID,
["source_id"] = newSourceID
})
end

function MEQUIVPA(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceData = IEex_GetActorShare(sourceID)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local savebonus = IEex_ReadDword(effectData + 0x40)
	local saveBonusStat = IEex_ReadByte(effectData + 0x44, 0x0)
	local saveBonusLevel = IEex_ReadByte(effectData + 0x45, 0x0)
	local requiredOldOrderLevel = IEex_ReadByte(effectData + 0x46, 0x0)
	local saveBonusStatDivisor = 2
	if bit.band(IEex_GetActorStat(sourceID, 89), 0x8) > 0 and IEex_GetActorStat(sourceID, 101) >= requiredOldOrderLevel then
		saveBonusStatDivisor = 1
	end
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	if casterlvl <= 0 then
		casterlvl = 1
	end
	savebonus = savebonus + math.floor(IEex_GetActorStat(sourceID, saveBonusLevel) / 2) + math.floor((IEex_GetActorStat(sourceID, saveBonusStat) - 10) / saveBonusStatDivisor)
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 288 and theparameter2 == 236 and bit.band(thesavingthrow, 0x10000) == 0 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if bit.band(thesavingthrow, 0x20000) == 0 then
				if theresource == "" or theresource == parent_resource then
					savebonus = savebonus + theparameter1
				end
			end
		end
	end)
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 288 and theparameter2 == 236 and bit.band(thesavingthrow, 0x10000) > 0 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if bit.band(thesavingthrow, 0x20000) == 0 then
				if theresource == "" or theresource == parent_resource then
					savebonus = savebonus + theparameter1
				end
			end
		end
	end)
	local newSavingThrow = 0
	if bit.band(savingthrow, 0x400) > 0 then
		newSavingThrow = bit.bor(newSavingThrow, 0x4)
	end
	if bit.band(savingthrow, 0x800) > 0 then
		newSavingThrow = bit.bor(newSavingThrow, 0x8)
	end
	if bit.band(savingthrow, 0x1000) > 0 then
		newSavingThrow = bit.bor(newSavingThrow, 0x10)
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["savingthrow"] = newSavingThrow,
["savebonus"] = savebonus,
["casterlvl"] = casterlvl,
["resource"] = spellRES,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
end
ex_stable_animations = {[0x7200] = true, [0x7201] = true, [0x7202] = true, [0x7203] = true, [0x7400] = true, [0x7401] = true, [0x7402] = true, [0x7900] = true, [0x7901] = true, [0x7902] = true, [0x7903] = true, [0x7A00] = true, [0x7A01] = true, [0x7A02] = true, [0x7A03] = true, [0x7A04] = true, [0x7B00] = true, [0x7B03] = true, [0x7F03] = true, [0x7F0A] = true, [0x7F0B] = true, [0x7F13] = true, [0x7F18] = true, [0x7F2F] = true, [0xA000] = true, [0xA100] = true, [0xAA20] = true, [0xB000] = true, [0xB100] = true, [0xC100] = true, [0xC300] = true, [0xC400] = true, [0xE000] = true, [0xE012] = true, [0xE022] = true, [0xE038] = true, [0xE048] = true, [0xE050] = true, [0xE218] = true, [0xE269] = true, [0xE289] = true, [0xE3BB] = true, [0xE468] = true, [0xE488] = true, [0xE908] = true, [0xE918] = true, [0xE928] = true, [0xEBB1] = true, [0xEBCD] = true, [0xEC33] = true, [0xED28] = true, [0xEF28] = true, [0xEF91] = true, [0xF50B] = true, [0xF51B] = true, }
function MEKNOCKD(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceData = IEex_GetActorShare(sourceID)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local savebonus = IEex_ReadDword(effectData + 0x40)
	local saveBonusLevel = IEex_ReadByte(effectData + 0x45, 0x0)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local knockdownFeatID = ex_feat_name_id["ME_KNOCKDOWN"]
	local knockdownFeatCount = 0
	if knockdownFeatID ~= nil then
		knockdownFeatCount = IEex_ReadByte(sourceData + 0x744 + knockdownFeatID, 0x0)
	end
	local newSavingThrow = 0
	local saveBonusStatBonus = IEex_GetActorStat(sourceID, 36)
	if IEex_GetActorStat(sourceID, 40) > saveBonusStatBonus then
		saveBonusStatBonus = IEex_GetActorStat(sourceID, 40)
		newSavingThrow = bit.bor(newSavingThrow, 0x8)
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = ex_tra_915,
["parent_resource"] = "USKNKDOM",
["source_id"] = sourceID
})
	else
		newSavingThrow = bit.bor(newSavingThrow, 0x4)
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = ex_tra_904,
["parent_resource"] = "USKNKDOM",
["source_id"] = sourceID
})
	end
	savebonus = savebonus + math.floor(IEex_GetActorBaseAttackBonus(sourceID, true) / 2) + math.floor((saveBonusStatBonus - 10) / 2)
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 288 and theparameter2 == 236 and bit.band(thesavingthrow, 0x10000) == 0 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if bit.band(thesavingthrow, 0x20000) == 0 then
				if theresource == "" or theresource == parent_resource then
					savebonus = savebonus + theparameter1
				end
			end
		end
	end)
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 288 and theparameter2 == 236 and bit.band(thesavingthrow, 0x10000) > 0 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if bit.band(thesavingthrow, 0x20000) == 0 then
				if theresource == "" or theresource == parent_resource then
					savebonus = savebonus + theparameter1
				end
			end
		end
	end)
	local race = IEex_ReadByte(creatureData + 0x26, 0x0)
	local animation = IEex_ReadDword(creatureData + 0x5C4)
	if race == 4 or race == 185 or ex_stable_animations[animation] then
		savebonus = savebonus - 4
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = 70,
["parameter1"] = -4,
["parameter2"] = 236,
["savingthrow"] = 0x10000,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 419,
["target"] = 2,
["timing"] = 0,
["duration"] = 4,
["parameter2"] = 1,
["savingthrow"] = newSavingThrow,
["savebonus"] = savebonus,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
end

function MEFEINT(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceData = IEex_GetActorShare(sourceID)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local savebonus = IEex_ReadDword(effectData + 0x40)
	local saveBonusLevel = IEex_ReadByte(effectData + 0x45, 0x0)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local feintFeatID = ex_feat_name_id["ME_FEINT"]
	local feintFeatCount = 0
	if feintFeatID ~= nil then
		feintFeatCount = IEex_ReadByte(sourceData + 0x744 + feintFeatID, 0x0)
	end
	savebonus = savebonus + IEex_GetActorStat(sourceID, 230)
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 288 and theparameter2 == 236 and bit.band(thesavingthrow, 0x10000) == 0 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if bit.band(thesavingthrow, 0x20000) == 0 then
				if theresource == "" or theresource == parent_resource then
					savebonus = savebonus + theparameter1
				end
			end
		end
	end)
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 288 and theparameter2 == 236 and bit.band(thesavingthrow, 0x10000) > 0 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if bit.band(thesavingthrow, 0x20000) == 0 then
				if theresource == "" or theresource == parent_resource then
					savebonus = savebonus + theparameter1
				end
			end
		end
	end)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = 70,
["parameter1"] = -4,
["parameter2"] = 236,
["savingthrow"] = 0x10000,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["savingthrow"] = 0x10,
["savebonus"] = savebonus,
["parent_resource"] = "USFEINTA",
["source_target"] = targetID,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 138,
["target"] = 2,
["timing"] = 0,
["parameter2"] = 4,
["savingthrow"] = 0x10,
["savebonus"] = savebonus,
["parent_resource"] = "USFEINTA",
["source_target"] = targetID,
["source_id"] = sourceID
})
--[[
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 0,
["parameter2"] = 7,
["savingthrow"] = 0x10,
["savebonus"] = savebonus,
["parent_resource"] = "USFEINTA",
["source_target"] = targetID,
["source_id"] = sourceID
})
--]]
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = 4,
["parameter2"] = 183,
["savebonus"] = savebonus,
["parent_resource"] = "USFEINTA",
["source_target"] = targetID,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 9,
["target"] = 2,
["timing"] = 0,
["duration"] = 4,
["parameter1"] = 0x14141400,
["parameter2"] = 0xF00FF,
["savingthrow"] = 0x10,
["savebonus"] = savebonus,
["parent_resource"] = "USFEINTA",
["source_target"] = targetID,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 0,
["duration"] = 4,
["parameter1"] = 0 - math.floor((IEex_GetActorStat(targetID, 40) - 10) / 2) - math.floor(IEex_ReadByte(sourceData + 0x7B6, 0x0) / 3),
["savingthrow"] = 0x10,
["savebonus"] = savebonus,
["parent_resource"] = "USFEINTA",
["source_target"] = targetID,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 54,
["target"] = 2,
["timing"] = 0,
["duration"] = 4,
["parameter1"] = 0 - math.floor(IEex_ReadByte(sourceData + 0x7B6, 0x0) / 3),
["savingthrow"] = 0x10,
["savebonus"] = savebonus,
["parent_resource"] = "USFEINTA",
["source_target"] = targetID,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USFREESP",
["source_id"] = sourceID
})
	if feintFeatCount >= 2 then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 188,
["target"] = 2,
["timing"] = 0,
["duration"] = 6,
["parameter2"] = 1,
["parent_resource"] = "USFREESP",
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 6,
["resource"] = "USFREESP",
["parent_resource"] = "USFREESP",
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 6,
["resource"] = "USFREESP",
["parent_resource"] = "USFREES2",
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 6,
["resource"] = "USFREES2",
["parent_resource"] = "USFREES2",
["source_id"] = sourceID
})
	end
end

function MEGRAPPL(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceData = IEex_GetActorShare(sourceID)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local savebonus = IEex_ReadDword(effectData + 0x40)
	local saveBonusLevel = IEex_ReadByte(effectData + 0x45, 0x0)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local newSavingThrow = 0
	local saveBonusStatBonus = IEex_GetActorStat(sourceID, 36)
	local handsUsed = 0
	local spriteHands = 2
	local animation = IEex_ReadDword(sourceData + 0x5C4)
	if extra_hands[animation] ~= nil then
		spriteHands = extra_hands[animation]
	end
--	if IEex_GetActorSpellState(sourceID, 241) then
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x20)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 241 then
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
				if (thespecial >= 3 and thespecial <= 5 and theparameter1 ~= 41) then
					if bit.band(thesavingthrow, 0x20000) == 0 then
						handsUsed = handsUsed + 1
					else
						handsUsed = handsUsed + 2
					end
				end
			end
		end)
--	end
	if handsUsed >= spriteHands then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = ex_tra_917,
["parent_resource"] = "USGRAPPM",
["source_id"] = sourceID
})
		return
	end
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = ex_tra_916,
["parent_resource"] = "USGRAPPM",
["source_id"] = sourceID
})
	if IEex_GetActorStat(sourceID, 40) > saveBonusStatBonus then
		saveBonusStatBonus = IEex_GetActorStat(sourceID, 40)
	end
	local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
	if IEex_CompareActorAllegiances(sourceID, targetID) < 1 or bit.band(stateValue, 0x29) == 0 then
		newSavingThrow = bit.bor(newSavingThrow, 0x8)
	end
	savebonus = savebonus + math.floor(IEex_GetActorBaseAttackBonus(sourceID, true) / 2) + math.floor((saveBonusStatBonus - 10) / 2)
	if handsUsed == 0 then
		savebonus = savebonus + 4
	end
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 288 and theparameter2 == 236 and bit.band(thesavingthrow, 0x10000) == 0 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if bit.band(thesavingthrow, 0x20000) == 0 then
				if theresource == "" or theresource == parent_resource then
					savebonus = savebonus + theparameter1
				end
			end
		end
	end)
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 288 and theparameter2 == 236 and bit.band(thesavingthrow, 0x10000) > 0 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if bit.band(thesavingthrow, 0x20000) == 0 then
				if theresource == "" or theresource == parent_resource then
					savebonus = savebonus + theparameter1
				end
			end
		end
	end)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = 70,
["parameter1"] = -4,
["parameter2"] = 236,
["savingthrow"] = 0x10000,
["resource"] = "USGRAPPD",
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter2"] = 13,
["resource"] = "MESPLPR2",
["parent_resource"] = "USGRAPPD",
["source_target"] = targetID,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 0,
["duration"] = 4,
["savingthrow"] = newSavingThrow,
["savebonus"] = savebonus,
["resource"] = "USGRAPPD",
["parent_resource"] = "USGRAPPD",
["source_target"] = targetID,
["source_id"] = sourceID
})
end

function MEGRAPP2(effectData, creatureData)
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = 14,
["parameter1"] = 0,
["parameter2"] = 241,
["special"] = 85,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
end

function MEDISARM(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceData = IEex_GetActorShare(sourceID)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = bit.band(IEex_ReadDword(effectData + 0x3C), 0xFFFFFFE3)
	local savebonus = IEex_ReadDword(effectData + 0x40)
	local saveBonusLevel = IEex_ReadByte(effectData + 0x45, 0x0)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local disarmFeatID = ex_feat_name_id["ME_DISARM"]
	local knockdownFeatCount = 0
	if knockdownFeatID ~= nil then
		knockdownFeatCount = IEex_ReadByte(sourceData + 0x744 + knockdownFeatID, 0x0)
	end
	local newSavingThrow = 0
	local saveBonusStatBonus = IEex_GetActorStat(sourceID, 36)
	if IEex_GetActorStat(sourceID, 40) > saveBonusStatBonus then
		saveBonusStatBonus = IEex_GetActorStat(sourceID, 40)
		newSavingThrow = bit.bor(newSavingThrow, 0x8)
	else
		newSavingThrow = bit.bor(newSavingThrow, 0x4)
	end
	savebonus = savebonus + math.floor(IEex_GetActorStat(sourceID, 95) / 2) + math.floor((saveBonusStatBonus - 10) / 2)
--	if IEex_GetActorSpellState(sourceID, 236) then
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 236 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				if theresource == parent_resource then
					savebonus = savebonus + theparameter1
				end
			end
		end)
--	end
--	if IEex_GetActorSpellState(targetID, 237) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 237 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				if theresource == parent_resource then
					savebonus = savebonus + theparameter1
				end
			end
		end)
--	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = 70,
["parameter1"] = -4,
["parameter2"] = 237,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
	if knockdownFeatCount < 2 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 290,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 13,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 419,
["target"] = 2,
["timing"] = 0,
["duration"] = 4,
["parameter2"] = 1,
["savingthrow"] = newSavingThrow,
["savebonus"] = savebonus,
["parent_resource"] = "USKNKDO",
["source_target"] = targetID,
["source_id"] = sourceID
})
end

function MESPLPRC(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local percentChance = IEex_ReadByte(effectData + 0x44, 0x0)
	local bonusStatMultiplier = IEex_ReadByte(effectData + 0x45, 0x0)
	local bonusStatDivisor = IEex_ReadByte(effectData + 0x46, 0x0)
	local bonusStat = IEex_ReadByte(effectData + 0x47, 0x0)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)

	local bonusStatValue = 0
	if bonusStat > 0 then
		bonusStatValue = IEex_GetActorStat(sourceID, bonusStat)
		if bonusStat >= 36 and bonusStat <= 42 then
			bonusStatValue = math.floor((bonusStatValue - 10) / 2)
		end
		if bonusStatMultiplier ~= 0 then
			bonusStatValue = bonusStatValue * bonusStatMultiplier
		end
		if bonusStatDivisor ~= 0 then
			bonusStatValue = math.floor(bonusStatValue / bonusStatDivisor)
		end
		percentChance = percentChance + bonusStatValue
	end
	if math.random(100) <= percentChance then
		IEex_ApplyEffectToActor(targetID, {
	["opcode"] = 402,
	["target"] = 2,
	["timing"] = 1,
	["casterlvl"] = casterlvl,
	["resource"] = spellRES,
	["parent_resource"] = parent_resource,
	["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
	["source_target"] = targetID,
	["source_id"] = sourceID
	})
	end
end

function EXADVREC(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local special = IEex_ReadDword(effectData + 0x44)
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local thespecial = IEex_ReadDword(eData + 0x48)
		local theparameter3 = IEex_ReadDword(eData + 0x60)
		if theopcode == 288 and theparameter2 == 197 and (special <= 0 or (special == thespecial and bit.band(thesavingthrow, 0x10000) > 0)) then
			while parameter1 > 0 and theparameter3 > 0 do
				parameter1 = parameter1 - 1
				theparameter3 = theparameter3 - 1
				IEex_WriteDword(effectData + 0x18, parameter1)
				IEex_WriteDword(eData + 0x60, theparameter3)
			end
		end
	end)
end

function MEMIRRIM(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local duration = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local foundIt = false
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		if theopcode == 119 then
			foundIt = true
			local numImages = IEex_ReadDword(eData + 0x1C)
			if parameter2 == 0 then
				numImages = numImages + parameter1
			elseif parameter2 == 1 then
				numImages = parameter1
			elseif parameter2 == 2 then
				numImages = math.floor(numImages * parameter1 / 100)
			end
			if numImages > 8 then
				numImages = 8
			elseif numImages < 0 then
				numImages = 0
			end
			IEex_WriteDword(eData + 0x1C, numImages)
			IEex_WriteDword(eData + 0x20, 0)
		end
	end)
	if foundIt == false and parameter2 == 0 then
		IEex_ApplyEffectToActor(targetID, {
	["opcode"] = 119,
	["target"] = 2,
	["timing"] = 0,
	["duration"] = duration,
	["parameter1"] = 1,
	["parameter2"] = 1,
	["parent_resource"] = parent_resource,
	["internal_flags"] = IEex_ReadDword(effectData + 0xD4),
	["source_id"] = sourceID
	})
		parameter1 = parameter1 - 1
		if parameter1 > 0 then
			IEex_IterateActorEffects(targetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				if theopcode == 119 then
					foundIt = true
					local numImages = IEex_ReadDword(eData + 0x1C)
					if parameter2 == 0 then
						numImages = numImages + parameter1
					elseif parameter2 == 1 then
						numImages = parameter1
					elseif parameter2 == 2 then
						numImages = math.floor(numImages * parameter1 / 100)
					end
					if numImages > 8 then
						numImages = 8
					elseif numImages < 0 then
						numImages = 0
					end
					IEex_WriteDword(eData + 0x1C, numImages)
					IEex_WriteDword(eData + 0x20, 0)
				end
			end)
		end
	end
end

function MEPOISON(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	if parameter2 == 0 then
		parameter1 = 1
		parameter2 = 2
	elseif parameter2 == 3 and (parameter1 == 6 or parameter1 == 7) then
		parameter1 = 1
		parameter2 = 4
	end
	local duration = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	if casterClass == 2 or casterClass == 10 or casterClass == 11 then
		duration = math.floor(duration * IEex_GetActorStat(sourceID, 53) / 100)
	elseif casterClass == 3 or casterClass == 4 or casterClass == 7 or casterClass == 8 then
		duration = math.floor(duration * IEex_GetActorStat(sourceID, 54) / 100)
	end
	local damageMultiplier = 100
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		if theopcode == 73 and theparameter2 == 6 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			damageMultiplier = damageMultiplier + theparameter1
		end
	end)
	parameter1 = math.floor(parameter1 * damageMultiplier / 100)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 25,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter1"] = parameter1,
["parameter2"] = parameter2,
["parent_resource"] = parent_resource,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_target"] = targetID,
["source_id"] = sourceID
})
end

function MEPOISOW(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadWord(effectData + 0x1C, 0x0)
	local duration = IEex_ReadWord(effectData + 0x1E, 0x0)
	local savebonus = IEex_ReadDword(effectData + 0x40)
	local special = IEex_ReadDword(effectData + 0x40)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local additionalDC = 0
	if bit.band(special, 0x1) > 0 then
		additionalDC = additionalDC + IEex_GetActorStat(sourceID, 25)
	end
	if bit.band(special, 0x2) > 0 then
		additionalDC = additionalDC + IEex_GetActorStat(sourceID, 25) * 2
	end
	if bit.band(special, 0x4) > 0 then
		additionalDC = additionalDC + IEex_GetActorStat(sourceID, 40)
	end
	if bit.band(special, 0x8) > 0 then
		additionalDC = additionalDC + IEex_GetActorStat(sourceID, 40) * 2
	end
	if bit.band(special, 0x10) > 0 then
		additionalDC = additionalDC + IEex_GetActorStat(sourceID, 38)
	end
	if bit.band(special, 0x20) > 0 then
		additionalDC = additionalDC + IEex_GetActorStat(sourceID, 38) * 2
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 25,
["target"] = 2,
["parameter1"] = parameter1,
["parameter2"] = parameter2,
["timing"] = 0,
["duration"] = duration,
["savingthrow"] = 0x4,
["savebonus"] = savebonus + additionalDC,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
end

function MEWOFOST(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local wallAlreadyExists = false
	IEex_IterateIDs(IEex_ReadDword(creatureData + 0x12), 0, function(id)
		local projectileData = IEex_GetActorShare(id)
		if IEex_ReadWord(projectileData + 0x6E, 0x0) == 303 then
			wallAlreadyExists = true
		end
	end)
	ex_woforc_positions = {0, {}}
	if spellRES ~= "" and not wallAlreadyExists then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 6,
["duration"] = IEex_GetGameTick() + IEex_ReadDword(effectData + 0x44),
["resource"] = spellRES,
["parent_resource"] = spellRES,
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["target_x"] = IEex_ReadDword(effectData + 0x84),
["target_y"] = IEex_ReadDword(effectData + 0x88),
["source_target"] = targetID,
["source_id"] = IEex_ReadDword(effectData + 0x10C),
})
	end
end


ex_key_angles = {-90, -67.5, -45, -22.5, 0, 22.5, 45, 67.5, 90}
ex_woforc_positions = {0, {}}
function MEWOFORC(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 0x1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local creatureRES = IEex_ReadLString(effectData + 0x18, 8)
	if creatureRES == "" then
		creatureRES = "USWOFORC"
	end
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local numCreatures = IEex_ReadWord(effectData + 0x44, 0x0)
	if numCreatures == 0 then return end
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local wallAnimation = ""
	local wallDeltaBase = 30
	local sourceX, sourceY = IEex_GetActorLocation(sourceID)
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	local casterOrientation = IEex_ReadByte(creatureData + 0x5380, 0x0)
	if casterOrientation > 8 then
		casterOrientation = casterOrientation - 8
	end
	local orientation = 0

	local wallAlreadyExists = false
	IEex_IterateIDs(IEex_ReadDword(creatureData + 0x12), 0, function(id)
		local projectileData = IEex_GetActorShare(id)
		if IEex_ReadWord(projectileData + 0x6E, 0x0) == 303 then
			orientation = IEex_ReadWord(IEex_ReadDword(projectileData + 0x192) + 0xC6, 0x0)
			if orientation == 0 and casterOrientation ~= 0 then
				orientation = casterOrientation
			elseif targetX > sourceX then
				orientation = 8 - orientation
			end

		end
	end)
	if bit.band(savingthrow, 0x20000000) > 0 then
		orientation = IEex_ReadWord(effectData + 0x46, 0x0)
		creatureRES = "USCOFORC"
	end
	local duration = IEex_ReadDword(effectData + 0x5C)
	local timing = 0
	if duration == 0 then
		timing = 9
		duration = 60
	end
	if bit.band(savingthrow, 0x10000000) > 0 then
		sourceX = IEex_ReadDword(effectData + 0x7C)
		sourceY = IEex_ReadDword(effectData + 0x80)
	end
	local deltaX = targetX - sourceX
	local deltaY = targetY - sourceY
	local angle = ex_key_angles[orientation + 1]
	local wallDeltaX = math.floor(math.sin(math.rad(angle)) * wallDeltaBase * -1)
	local wallDeltaY = math.floor(math.cos(math.rad(angle)) * wallDeltaBase)
	local areaRES = ""
	if IEex_ReadDword(creatureData + 0x12) > 0 then
		areaRES = IEex_ReadLString(IEex_ReadDword(creatureData + 0x12), 8)
	end
	local resWrapper = IEex_DemandRes(areaRES .. "SR", "BMP")
	if not resWrapper:isValid() then
		resWrapper:free()
		return
	end
	local bitmapData = resWrapper:getData()
	local fileSize = IEex_ReadDword(bitmapData + 0x2)
	local dataOffset = IEex_ReadDword(bitmapData + 0xA)
	local bitmapX = IEex_ReadDword(bitmapData + 0x12)
	local bitmapY = IEex_ReadDword(bitmapData + 0x16)
	local padding = (bitmapX / 2) % 4
	local areaX = bitmapX * 16
	local areaY = bitmapY * 12
	local pixelSizeX = 16
	local pixelSizeY = 12
	local current = 0
	local currentA = 0
	local currentB = 0
	local currentX = 0
	local currentY = 0
	local x = 0
	local y = 0
	local trueBitmapX = math.floor(bitmapX / 2) + padding
--	ex_woforc_positions = {0, {}}
	if numCreatures % 2 == 1 then
--[[
		x = math.floor(targetX / pixelSizeX)
		y = bitmapY - math.floor((targetY + 7) / pixelSizeY)
		if y < 1 then
			y = 1
		end
		current = IEex_ReadByte(bitmapData + dataOffset + y * trueBitmapX + math.floor(x / 2), 0x0)
		if ex_default_terrain_table_1[math.floor(current / 16) + 1] ~= -1 and ex_default_terrain_table_1[(current % 16) + 1] ~= -1 then
			IEex_Eval('CreateCreature(\"' .. creatureRES .. '\", \"USWOFORC\", [' .. targetX .. '.' .. targetY + 7 .. '], ' .. 0, sourceID)
		end
--]]
		table.insert(ex_woforc_positions[2], {targetX, targetY + 7})
		IEex_Eval('CreateCreature(\"' .. creatureRES .. '\", \"' .. creatureRES .. '\", [' .. targetX .. '.' .. targetY + 7 .. '], ' .. 0, sourceID)
--[[
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 67,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter2"] = 2,
["resource"] = creatureRES,
["vvcresource"] = vvcresource,
["casterlvl"] = casterlvl,
["source_target"] = sourceID,
["source_id"] = sourceID,
["source_x"] = sourceX,
["source_y"] = sourceY,
["target_x"] = targetX,
["target_y"] = targetY
})
--]]
		numCreatures = math.floor((numCreatures - 1) / 2)
		for i = 1, numCreatures, 1 do
--[[
			x = math.floor((targetX + (wallDeltaX * i)) / pixelSizeX)
			y = bitmapY - math.floor((targetY + (wallDeltaY * i) + 7) / pixelSizeY)
			if y < 1 then
				y = 1
			end
			current = IEex_ReadByte(bitmapData + dataOffset + y * trueBitmapX + math.floor(x / 2), 0x0)
			if ex_default_terrain_table_1[math.floor(current / 16) + 1] ~= -1 and ex_default_terrain_table_1[(current % 16) + 1] ~= -1 then
				IEex_Eval('CreateCreature(\"' .. creatureRES .. '\", \"USWOFORC\", [' .. targetX + (wallDeltaX * i) .. '.' .. targetY + (wallDeltaY * i) + 7 .. '], ' .. 0, sourceID)
			end
--]]
			table.insert(ex_woforc_positions[2], {targetX + (wallDeltaX * i), targetY + (wallDeltaY * i) + 7})
			IEex_Eval('CreateCreature(\"' .. creatureRES .. '\", \"' .. creatureRES .. '\", [' .. targetX + (wallDeltaX * i) .. '.' .. targetY + (wallDeltaY * i) + 7 .. '], ' .. 0, sourceID)


--[[
			IEex_ApplyEffectToActor(sourceID, {
	["opcode"] = 67,
	["target"] = 2,
	["timing"] = timing,
	["duration"] = duration,
	["parameter2"] = 2,
	["resource"] = creatureRES,
	["vvcresource"] = vvcresource,
	["casterlvl"] = casterlvl,
	["source_target"] = sourceID,
	["source_id"] = sourceID,
	["source_x"] = sourceX,
	["source_y"] = sourceY,
	["target_x"] = targetX + (wallDeltaX * i),
	["target_y"] = targetY + (wallDeltaY * i)
	})
--]]

--[[
			x = math.floor((targetX - (wallDeltaX * i)) / pixelSizeX)
			y = bitmapY - math.floor((targetY - (wallDeltaY * i) + 7) / pixelSizeY)
			if y < 1 then
				y = 1
			end
			current = IEex_ReadByte(bitmapData + dataOffset + y * trueBitmapX + math.floor(x / 2), 0x0)
			if ex_default_terrain_table_1[math.floor(current / 16) + 1] ~= -1 and ex_default_terrain_table_1[(current % 16) + 1] ~= -1 then
				IEex_Eval('CreateCreature(\"' .. creatureRES .. '\", \"USWOFORC\", [' .. targetX - (wallDeltaX * i) .. '.' .. targetY - (wallDeltaY * i) + 7 .. '], ' .. 0, sourceID)
			end
--]]
			table.insert(ex_woforc_positions[2], {targetX - (wallDeltaX * i), targetY - (wallDeltaY * i) + 7})
			IEex_Eval('CreateCreature(\"' .. creatureRES .. '\", \"' .. creatureRES .. '\", [' .. targetX - (wallDeltaX * i) .. '.' .. targetY - (wallDeltaY * i) + 7 .. '], ' .. 0, sourceID)
--[[
			IEex_ApplyEffectToActor(sourceID, {
	["opcode"] = 67,
	["target"] = 2,
	["timing"] = timing,
	["duration"] = duration,
	["parameter2"] = 2,
	["resource"] = creatureRES,
	["vvcresource"] = vvcresource,
	["casterlvl"] = casterlvl,
	["source_target"] = sourceID,
	["source_id"] = sourceID,
	["source_x"] = sourceX,
	["source_y"] = sourceY,
	["target_x"] = targetX - (wallDeltaX * i),
	["target_y"] = targetY - (wallDeltaY * i)
	})
--]]
		end
	else
		for i = 1, numCreatures, 1 do
			table.insert(ex_woforc_positions[2], {targetX + math.floor(wallDeltaX / 2) + (wallDeltaX * i), targetY + math.floor(wallDeltaY / 2) + (wallDeltaY * i) + 7})
			IEex_Eval('CreateCreature(\"' .. creatureRES .. '\", \"' .. creatureRES .. '\", [' .. targetX + math.floor(wallDeltaX / 2) + (wallDeltaX * i) .. '.' .. targetY + math.floor(wallDeltaY / 2) + (wallDeltaY * i) + 7 .. '], ' .. 0, sourceID)
--[[
			IEex_ApplyEffectToActor(sourceID, {
	["opcode"] = 67,
	["target"] = 2,
	["timing"] = timing,
	["duration"] = duration,
	["parameter2"] = 2,
	["resource"] = creatureRES,
	["vvcresource"] = vvcresource,
	["casterlvl"] = casterlvl,
	["source_target"] = sourceID,
	["source_id"] = sourceID,
	["source_x"] = sourceX,
	["source_y"] = sourceY,
	["target_x"] = targetX + math.floor(wallDeltaX / 2) + (wallDeltaX * i),
	["target_y"] = targetY + math.floor(wallDeltaY / 2) + (wallDeltaY * i)
	})
--]]
			table.insert(ex_woforc_positions[2], {targetX - math.floor(wallDeltaX / 2) - (wallDeltaX * i), targetY - math.floor(wallDeltaY / 2) - (wallDeltaY * i) + 7})
			IEex_Eval('CreateCreature(\"' .. creatureRES .. '\", \"' .. creatureRES .. '\", [' .. targetX - math.floor(wallDeltaX / 2) - (wallDeltaX * i) .. '.' .. targetY - math.floor(wallDeltaY / 2) - (wallDeltaY * i) + 7 .. '], ' .. 0, sourceID)
--[[
			IEex_ApplyEffectToActor(sourceID, {
	["opcode"] = 67,
	["target"] = 2,
	["timing"] = timing,
	["duration"] = duration,
	["parameter2"] = 2,
	["resource"] = creatureRES,
	["vvcresource"] = vvcresource,
	["casterlvl"] = casterlvl,
	["source_target"] = sourceID,
	["source_id"] = sourceID,
	["source_x"] = sourceX,
	["source_y"] = sourceY,
	["target_x"] = targetX - math.floor(wallDeltaX / 2) - (wallDeltaX * i),
	["target_y"] = targetY - math.floor(wallDeltaY / 2) - (wallDeltaY * i)
	})
--]]
		end
	end
	resWrapper:free()
end

function MEWOFOR2(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MEWOFOR2", 5) then return end
	local wallAlreadyExists = false
	IEex_IterateIDs(IEex_ReadDword(creatureData + 0x12), 0, function(id)
		local projectileData = IEex_GetActorShare(id)
		if IEex_ReadWord(projectileData + 0x6E, 0x0) == 303 then
			wallAlreadyExists = true
		end
	end)

	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	if bit.band(extraFlags, 0x800000) == 0 and IEex_GetGameTick() - IEex_ReadDword(effectData + 0x68) >= 1 then
		IEex_WriteDword(creatureData + 0x740, bit.bor(extraFlags, 0x800000))
		local nextPosition = ex_woforc_positions[1] + 1
		local numPositions = #ex_woforc_positions[2]
		ex_woforc_positions[1] = nextPosition
		if nextPosition <= numPositions then
			IEex_PreventMovingAttacksOfOpportunity(targetID, 10)
			IEex_JumpActorToPoint(targetID, ex_woforc_positions[2][nextPosition][1], ex_woforc_positions[2][nextPosition][2], true)
--[[
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["savingthrow"] = 0x10000,
["target_x"] = ex_woforc_positions[2][nextPosition][1],
["target_y"] = ex_woforc_positions[2][nextPosition][2],
["source_target"] = targetID,
["source_id"] = targetID,
})
--]]
		end
	elseif not wallAlreadyExists then
		IEex_WriteByte(creatureData + 0x25, 105)
	end
end

function MECOFORC(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 0x1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local special = IEex_ReadDword(effectData + 0x44)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - time_applied) / 15)
	end
	local areaData = IEex_ReadDword(creatureData + 0x12)
	if areaData <= 0 then return end
	local areaRES = IEex_ReadLString(areaData, 8)
	local alreadyActive = false
	local notLoaded = true
	IEex_IterateIDs(areaData, 0x30, function(staticID)
		local staticData = IEex_GetActorShare(staticID)
		local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
		if scriptName == areaRES .. "COFL" then
			notLoaded = false
			if bit.band(IEex_ReadWord(staticData + 0xA2, 0x0), 0x1) > 0 then
				alreadyActive = true
			end
		end
	end)
	if alreadyActive or notLoaded then return end

	IEex_IterateIDs(areaData, 0x31, function(currentID)
		local currentShare = IEex_GetActorShare(currentID)
		local scriptName = IEex_ReadLString(currentShare + 0x554, 32)
		if scriptName == areaRES .. "AREAGL" then
			IEex_ApplyEffectToActor(currentID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter2"] = 230,
["special"] = 0x10000,
["savingthrow"] = 0x10000,
["casterlvl"] = casterlvl,
["source_target"] = currentID,
["source_id"] = currentID,
})
		end
	end)

	IEex_Eval('Activate(\"' .. areaRES .. 'COFL' .. '\")',sourceID)
	IEex_Eval('Activate(\"' .. areaRES .. 'COFR' .. '\")',sourceID)
	IEex_Eval('Activate(\"' .. areaRES .. 'COFB' .. '\")',sourceID)
	IEex_Eval('Activate(\"' .. areaRES .. 'COFT' .. '\")',sourceID)
	IEex_IterateIDs(areaData, 0x30, function(staticID)
		local staticData = IEex_GetActorShare(staticID)
		local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
		if scriptName == areaRES .. "COFL" then
			IEex_WriteDword(staticData + 0x6, targetX - 65)
			IEex_WriteDword(staticData + 0xA, targetY)
			IEex_WriteWord(staticData + 0x8E, targetX - 65)
			IEex_WriteWord(staticData + 0x90, targetY)
		elseif scriptName == areaRES .. "COFR" then
			IEex_WriteDword(staticData + 0x6, targetX + 65)
			IEex_WriteDword(staticData + 0xA, targetY)
			IEex_WriteWord(staticData + 0x8E, targetX + 65)
			IEex_WriteWord(staticData + 0x90, targetY)
		elseif scriptName == areaRES .. "COFB" then
			IEex_WriteDword(staticData + 0x6, targetX)
			IEex_WriteDword(staticData + 0xA, targetY + 45)
			IEex_WriteWord(staticData + 0x8E, targetX)
			IEex_WriteWord(staticData + 0x90, targetY + 45)
		elseif scriptName == areaRES .. "COFT" then
			IEex_WriteDword(staticData + 0x6, targetX)
			IEex_WriteDword(staticData + 0xA, targetY - 65)
			IEex_WriteWord(staticData + 0x8E, targetX)
			IEex_WriteWord(staticData + 0x90, targetY - 65)
		end
	end)
	ex_woforc_positions = {0, {}}
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 0x5,
["savingthrow"] = 0x20000000,
["resource"] = "MEWOFORC",
["casterlvl"] = casterlvl,
["source_target"] = targetID,
["source_id"] = sourceID,
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = targetX,
["target_y"] = targetY + 45
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 0x80005,
["savingthrow"] = 0x20000000,
["resource"] = "MEWOFORC",
["casterlvl"] = casterlvl,
["source_target"] = targetID,
["source_id"] = sourceID,
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = targetX,
["target_y"] = targetY - 65
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 0x40003,
["savingthrow"] = 0x20000000,
["resource"] = "MEWOFORC",
["casterlvl"] = casterlvl,
["source_target"] = targetID,
["source_id"] = sourceID,
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = targetX + 65,
["target_y"] = targetY
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 0x40003,
["savingthrow"] = 0x20000000,
["resource"] = "MEWOFORC",
["casterlvl"] = casterlvl,
["source_target"] = targetID,
["source_id"] = sourceID,
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = targetX - 65,
["target_y"] = targetY
})
end

function MECOFOR2(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MEWOFOR2", 5) then return end
--[[
	local wallAlreadyExists = false

	local areaData = IEex_ReadDword(creatureData + 0x12)

	if areaData <= 0 then
		wallAlreadyExists = true
	else
		local areaRES = IEex_ReadLString(areaData, 8)
		IEex_IterateIDs(areaData, 0x30, function(staticID)
			local staticData = IEex_GetActorShare(staticID)
			local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
			if scriptName == areaRES .. "COFL" and bit.band(IEex_ReadWord(staticData + 0xA2, 0x0), 0x1) > 0 then
				wallAlreadyExists = true
			end
		end)
	end
--]]

	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	if bit.band(extraFlags, 0x800000) == 0 and IEex_GetGameTick() - IEex_ReadDword(effectData + 0x68) >= 1 then
		IEex_WriteDword(creatureData + 0x740, bit.bor(extraFlags, 0x800000))
		local nextPosition = ex_woforc_positions[1] + 1
		local numPositions = #ex_woforc_positions[2]
		ex_woforc_positions[1] = nextPosition
		if nextPosition <= numPositions then
			IEex_PreventMovingAttacksOfOpportunity(targetID, 10)
			IEex_JumpActorToPoint(targetID, ex_woforc_positions[2][nextPosition][1], ex_woforc_positions[2][nextPosition][2], true)
--[[
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["savingthrow"] = 0x10000,
["target_x"] = ex_woforc_positions[2][nextPosition][1],
["target_y"] = ex_woforc_positions[2][nextPosition][2],
["source_target"] = targetID,
["source_id"] = targetID,
})
--]]
		end
--	elseif not wallAlreadyExists then
--		IEex_WriteByte(creatureData + 0x25, 105)
	end
end

function METORNAD(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 0x1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local special = IEex_ReadDword(effectData + 0x44)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - time_applied) / 15)
	end
	local areaData = IEex_ReadDword(creatureData + 0x12)
	if areaData <= 0 then return end
	local areaRES = IEex_ReadLString(areaData, 8)
	local alreadyActive = false
	local notLoaded = true
--[[
	local CGameStatic = IEex_CreateStatic(areaData, {
["name"] = "AR6300TORNA2",
["locX"] = targetX,
["locY"] = targetY,
["locZ"] = 1,
["animationResRef"] = "WHIRLWX",
["appearanceFlags"] = 0x3,
})
--]]
--	if true then return end
	IEex_IterateIDs(areaData, 0x30, function(staticID)
		local staticData = IEex_GetActorShare(staticID)
		local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
		if scriptName == areaRES .. "TORNAD" then
			notLoaded = false
			if bit.band(IEex_ReadWord(staticData + 0xA2, 0x0), 0x1) > 0 then
				alreadyActive = true
			end
		end
	end)
	if alreadyActive or notLoaded then return end

	IEex_IterateIDs(areaData, 0x31, function(currentID)
		local currentShare = IEex_GetActorShare(currentID)
		local scriptName = IEex_ReadLString(currentShare + 0x554, 32)
		if scriptName == areaRES .. "AREAGL" then
			IEex_ApplyEffectToActor(currentID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["resource"] = spellRES,
["parameter2"] = 230,
["special"] = 0x20000,
["savingthrow"] = 0x10000,
["casterlvl"] = casterlvl,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_target"] = currentID,
["source_id"] = sourceID,
})
		end
	end)

	IEex_Eval('Activate(\"' .. areaRES .. 'TORNAD' .. '\")',sourceID)
	IEex_IterateIDs(areaData, 0x30, function(staticID)
		local staticData = IEex_GetActorShare(staticID)
		local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
		if scriptName == areaRES .. "TORNAD" then
			IEex_WriteDword(staticData + 0x6, targetX)
			IEex_WriteDword(staticData + 0xA, targetY)
			IEex_WriteWord(staticData + 0x8E, targetX)
			IEex_WriteWord(staticData + 0x90, targetY)
			IEex_WriteDword(staticData + 0x190, 1)
		end
	end)
end

--ex_tornado_teleport_offsets = {{0, -2}, {1, -2}, {2, -2}, {2, -1}, {2, 0}, {2, 1}, {2, 2}, {1, 2}, {0, 2}, {-1, 2}, {-2, 2}, {-2, 1}, {-2, 0}, {-2, -1}, {-2, -2}, {-1, -2}}
ex_tornado_teleport_offsets = {{0, -1.41}, {.54, -1.31}, {1, -1}, {1.31, -.54}, {1.41, 0}, {1.31, .54}, {1, 1}, {.54, 1.31}, {0, 1.41}, {-.54, 1.31}, {-1, 1}, {-1.31, .54}, {-1.41, 0}, {-1.31, -.54}, {-1, -1}, {-.54, -1.31}}
ex_tornado_teleport_index = {}
function METORNAT(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
	local animation = IEex_ReadDword(creatureData + 0x5C4)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local projectileX = IEex_ReadDword(effectData + 0x84)
	local projectileY = IEex_ReadDword(effectData + 0x88)
	local shortestDistance = 0x7FFFFFFF
--[[
	IEex_IterateIDs(IEex_ReadDword(creatureData + 0x14), 80, function(actorID)
		local projectileData = IEex_GetActorShare(actorID)
		if IEex_ReadWord(projectileData + 0x48, 0x0) + 1 == ex_tornado_projectile then
			local currentX = IEex_ReadDword(projectileData + 0x8)
			local currentY = IEex_ReadDword(projectileData + 0xC)
			local currentDistance = IEex_GetDistance(targetX, targetY, currentX, currentY)
			if currentDistance < shortestDistance then
				shortestDistance = currentDistance
				projectileX = currentX
				projectileY = currentY
			end
		end
	end)
--]]
	local deltaX = targetX - projectileX
	local deltaY = targetY - projectileY
	if ex_tornado_teleport_index[targetID] == nil then
		local closestOffset = 0
		local closestOffsetDistance = 0x7FFFFFFF
		for i = 1, 16, 1 do
			local currentOffsetDistance = IEex_GetDistance(targetX, targetY, projectileX + math.floor(ex_tornado_teleport_offsets[i][1] * 10), projectileY + math.floor(ex_tornado_teleport_offsets[i][2] * 10))
			if currentOffsetDistance < closestOffsetDistance then
				closestOffsetDistance = currentOffsetDistance
				closestOffset = i
			end
		end
		ex_tornado_teleport_index[targetID] = closestOffset
	elseif ex_tornado_teleport_index[targetID] >= 16 then
		ex_tornado_teleport_index[targetID] = 1
	else
		ex_tornado_teleport_index[targetID] = ex_tornado_teleport_index[targetID] + 1
	end
	local targetHeight = IEex_ReadDword(creatureData + 0xE) * -1
	local newX = projectileX + math.floor(ex_tornado_teleport_offsets[ex_tornado_teleport_index[targetID]][1] * 2 * (targetHeight / 10 + 5))
	local newY = projectileY + math.floor(ex_tornado_teleport_offsets[ex_tornado_teleport_index[targetID]][2] * 2 * (targetHeight / 10 + 5))
--[[
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "METORNAT",
["source_target"] = targetID,
["source_id"] = sourceID
})
--]]
	IEex_PreventMovingAttacksOfOpportunity(targetID, 10)
	IEex_JumpActorToPoint(targetID, newX, newY, true)
--[[
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = newX,
["target_y"] = newY,
["parent_resource"] = "METORNAT",
["source_target"] = targetID,
["source_id"] = sourceID
})
--]]
	if IEex_GetGameTick() % 15 == 0 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = 0x30800,
["parameter2"] = 0x1000000,
["savingthrow"] = 0x4010000,
["resource"] = "EXDAMAGE",
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["source_target"] = targetID,
["source_id"] = sourceID
})
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = 5,
["parameter2"] = 13,
["savingthrow"] = 0x10000,
["resource"] = "MESPLPR2",
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["source_target"] = targetID,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 7,
["duration"] = IEex_GetGameTick(),
["parameter1"] = 30,
["parameter2"] = 1,
["special"] = -100,
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = newX + ex_tornado_teleport_offsets[((ex_tornado_teleport_index[targetID] - 5) % 16) + 1][1] * 20,
["target_y"] = newY + ex_tornado_teleport_offsets[((ex_tornado_teleport_index[targetID] - 5) % 16) + 1][2] * 20,
["resource"] = "MEWINGBU",
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["source_target"] = targetID,
["source_id"] = sourceID
})
end

function MEPRISWL(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 0x1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local special = IEex_ReadDword(effectData + 0x44)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local sourceX, sourceY = IEex_GetActorLocation(sourceID)
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	local distX = targetX - sourceX
	local distY = targetY - sourceY
	local dist = math.floor((distX ^ 2 + distY ^ 2) ^ .5)
	local orientation = 0
	if dist == 0 then
		dist = 1
	end
	local angle = 90
	if deltaX ~= 0 then
		angle = math.deg(math.atan(distY / distX))
		for i = 1, 9, 1 do
			if (angle >= key_angles[i] and angle - 11.25 <= key_angles[i]) or (angle <= key_angles[i] and angle + 11.25 >= key_angles[i]) then
				angle = key_angles[i]
				orientation = i - 1
			end
		end
	else
		if deltaY >= 0 then
			angle = key_angles[1]
			orientation = 0
		else
			angle = key_angles[9]
			orientation = 8
		end
	end
	
	local betweenWallsX = math.floor(math.cos(math.rad(angle)) * 20)
	local betweenWallsY = math.floor(math.sin(math.rad(angle)) * 20)
	for k, v in ipairs(key_angles) do
		if angle == v then
		end
	end
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - time_applied) / 15)
	end
	local areaData = IEex_ReadDword(creatureData + 0x12)
	if areaData <= 0 then return end
	local areaRES = IEex_ReadLString(areaData, 8)
	local alreadyActive = false
	local notLoaded = true
	IEex_IterateIDs(areaData, 0x30, function(staticID)
		local staticData = IEex_GetActorShare(staticID)
		local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
		if scriptName == areaRES .. "PRISW1" or scriptName == areaRES .. "PRISW2" or scriptName == areaRES .. "PRISW3" or scriptName == areaRES .. "PRISW4" or scriptName == areaRES .. "PRISW5" or scriptName == areaRES .. "PRISW6" or scriptName == areaRES .. "PRISW7" then
			notLoaded = false
			if bit.band(IEex_ReadWord(staticData + 0xA2, 0x0), 0x1) > 0 then
				alreadyActive = true
			end
		end
	end)
	if alreadyActive or notLoaded then return end

	IEex_IterateIDs(areaData, 0x31, function(currentID)
		local currentShare = IEex_GetActorShare(currentID)
		local scriptName = IEex_ReadLString(currentShare + 0x554, 32)
		if scriptName == areaRES .. "AREAGL" then
			IEex_ApplyEffectToActor(currentID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["resource"] = spellRES,
["parameter2"] = 230,
["parameter3"] = orientation,
["special"] = 0x80000,
["savingthrow"] = 0x10000,
["casterlvl"] = casterlvl,
["source_x"] = sourceX,
["source_y"] = sourceY,
["internal_flags"] = internalFlags,
["source_target"] = currentID,
["source_id"] = sourceID,
})
		end
	end)
	for i = 1, 7, 1 do
		IEex_Eval('Activate(\"' .. areaRES .. 'PRISW' .. i .. '\")',sourceID)
	end
	IEex_IterateIDs(areaData, 0x30, function(staticID)
		local staticData = IEex_GetActorShare(staticID)
		local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
		for i = 1, 7, 1 do
			if scriptName == areaRES .. "PRISW" .. i then
				if distX >= 0 then
					IEex_WriteDword(staticData + 0x6, targetX + (betweenWallsX * (7 - i)))
					IEex_WriteDword(staticData + 0xA, targetY + (betweenWallsY * (7 - i)))
					IEex_WriteWord(staticData + 0x8E, targetX + (betweenWallsX * (7 - i)))
					IEex_WriteWord(staticData + 0x90, targetY + (betweenWallsY * (7 - i)))
				else
					IEex_WriteDword(staticData + 0x6, targetX - (betweenWallsX * (7 - i)))
					IEex_WriteDword(staticData + 0xA, targetY - (betweenWallsY * (7 - i)))
					IEex_WriteWord(staticData + 0x8E, targetX - (betweenWallsX * (7 - i)))
					IEex_WriteWord(staticData + 0x90, targetY - (betweenWallsY * (7 - i)))
				end
				IEex_WriteWord(staticData + 0x180, orientation)
				IEex_WriteDword(staticData + 0x190, 1)
			end
		end
	end)
end

function MEREVGRV(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 0x1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local special = IEex_ReadDword(effectData + 0x44)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - time_applied) / 15)
	end
	local areaData = IEex_ReadDword(creatureData + 0x12)
	if areaData <= 0 then return end
	local areaRES = IEex_ReadLString(areaData, 8)
	local alreadyActive = false
	local notLoaded = true
	IEex_IterateIDs(areaData, 0x30, function(staticID)
		local staticData = IEex_GetActorShare(staticID)
		local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
		if scriptName == areaRES .. "GRVGLB" then
			notLoaded = false
			if bit.band(IEex_ReadWord(staticData + 0xA2, 0x0), 0x1) > 0 then
				alreadyActive = true
			end
		end
	end)
	if alreadyActive or notLoaded then return end

	IEex_IterateIDs(areaData, 0x31, function(currentID)
		local currentShare = IEex_GetActorShare(currentID)
		local scriptName = IEex_ReadLString(currentShare + 0x554, 32)
		if scriptName == areaRES .. "AREAGL" then
			IEex_ApplyEffectToActor(currentID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["resource"] = spellRES,
["parameter2"] = 230,
["special"] = 0x40000,
["savingthrow"] = 0x10000,
["casterlvl"] = casterlvl,
["internal_flags"] = internalFlags,
["source_target"] = currentID,
["source_id"] = sourceID,
})
		end
	end)
	IEex_Eval('Activate(\"' .. areaRES .. 'GRVGLB' .. '\")',sourceID)
	IEex_IterateIDs(areaData, 0x30, function(staticID)
		local staticData = IEex_GetActorShare(staticID)
		local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
		if scriptName == areaRES .. "GRVGLB" then
--		if scriptName == areaRES .. "GRVGL1" or scriptName == areaRES .. "GRVGL2" or scriptName == areaRES .. "GRVGL3" or scriptName == areaRES .. "GRVGL4" then
			IEex_WriteDword(staticData + 0x6, targetX)
			IEex_WriteDword(staticData + 0xA, targetY)
			IEex_WriteWord(staticData + 0x8E, targetX)
			IEex_WriteWord(staticData + 0x90, targetY)
			IEex_WriteDword(staticData + 0x190, 1)
		end
	end)
end
ex_grvglb_radius = 224
function MEGRVGLB(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 0x1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
	local centerX = IEex_ReadDword(effectData + 0x84)
	local centerY = IEex_ReadDword(effectData + 0x88)
	local horizontalDistance = math.floor((((targetX - centerX) ^ 2) + (((targetY - centerY) * 1.5) ^ 2)) ^ .5)
	if horizontalDistance > ex_grvglb_radius then
		horizontalDistance = ex_grvglb_radius
	end
	local globeYRadius = math.floor(((ex_grvglb_radius ^ 2) - (horizontalDistance ^ 2)) ^ .5)
	local globeHeight = globeYRadius + ex_grvglb_radius * .8
	local globeBottom = ex_grvglb_radius * .8 - globeYRadius

	local height = IEex_ReadSignedWord(creatureData + 0x720, 0x0)
	if height >= globeBottom and (height <= globeHeight or horizontalDistance <= ex_grvglb_radius * .6) then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter1"] = 5,
["parameter2"] = 190,
["special"] = 3,
["parent_resource"] = "MEGRVGLA",
["source_target"] = targetID,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
--["duration"] = IEex_GetGameTick() + 1,
["resource"] = "MEGRVGLA",
["parent_resource"] = "MEGRVGLA",
["source_target"] = targetID,
["source_id"] = sourceID
})
	else
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = "MEGRVGLA",
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
	end
	if height <= globeHeight and height >= globeBottom then

		if IEex_IsFlying(targetID) then return end

		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter1"] = globeHeight,
["parameter2"] = 190,
["special"] = 5,
["parent_resource"] = "MEGRVGLB",
["source_target"] = targetID,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
--["duration"] = IEex_GetGameTick() + 1,
["resource"] = "MEGRVGLB",
["parent_resource"] = "MEGRVGLB",
["source_target"] = targetID,
["source_id"] = sourceID
})
--		if IEex_ReadDword(creatureData + 0x556E) > 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["duration"] = 70,
["parameter1"] = IEex_ReadByte(creatureData + 0x72EA, 0x0),
["parameter2"] = 1,
--["special"] = -10000,
["savingthrow"] = 0x100000,
["resource"] = "MEWINGBU",
["parent_resource"] = "MEGRVGLC",
["target_x"] = targetX,
["target_y"] = targetY,
["source_target"] = targetID,
["source_id"] = sourceID
})
--[[
		else
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["duration"] = 70,
["parameter1"] = IEex_ReadByte(creatureData + 0x72EA, 0x0),
["parameter2"] = 3,
--["special"] = -10000,
["resource"] = "MEWINGBU",
["parent_resource"] = "MEGRVGLC",
["target_x"] = targetX,
["target_y"] = targetY,
["source_target"] = targetID,
["source_id"] = sourceID
})
		end
--]]
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 3,
["parameter1"] = -3,
["parameter2"] = 1,
["special"] = 2,
["resource"] = "MEHGTST",
["parent_resource"] = "MEGRVGLC",
["source_target"] = targetID,
["source_id"] = sourceID
})

			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["duration"] = 70,
["parameter1"] = globeHeight,
["parameter2"] = 1,
["resource"] = "MEHGTMOD",
["parent_resource"] = "MEGRVGLC",
["source_target"] = targetID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 70,
--["duration"] = IEex_GetGameTick() + 1,
["resource"] = "MEGRVGLC",
["parent_resource"] = "MEGRVGLC",
["source_target"] = targetID,
["source_id"] = sourceID
})
--[[
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 4,
["duration"] = 1,
["resource"] = "MEGRVGLB",
["parent_resource"] = "MEGRVGLB",
["source_target"] = targetID,
["source_id"] = targetID
})
--]]
	else
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = "MEGRVGLB",
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
	end
end
staticsToStop = {}
function EXVISEFF(effectData, creatureData, isSpecialCall)
	local constantID = IEex_ReadDword(effectData + 0x5C)
	if not isSpecialCall and constantID ~= 0 then return end
--	IEex_WriteDword(effectData + 0x110, 0x1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local visualEffectName = IEex_ReadLString(effectData + 0x18, 8)
	local visualEffectRES = visualEffectName
	local visualEffectLocZ = 0
	local visualEffectFlags = 0x3
	local visualEffectCycle = 0
	local visualEffectBlankFrames = 0
	local visualEffectEnlarge = false
	local visualEffectEnlargeOnLargeTarget = false
	local visualEffect = ex_custom_visual_effects[visualEffectName]
	if visualEffect then 
		visualEffectRES = visualEffect["animationResRef"]
		visualEffectLocZ = visualEffect["locZ"]
		visualEffectFlags = visualEffect["appearanceFlags"]
		visualEffectCycle = visualEffect["cycle"]
		visualEffectEnlarge = visualEffect["enlarge"]
		visualEffectEnlargeOnLargeTarget = visualEffect["enlargeOnLargeTarget"]
		if visualEffect["blankFrames"] then
			visualEffectBlankFrames = visualEffect["blankFrames"]
		end
	end
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local initializing = false
	if constantID == 0 then
		constantID = IEex_GetGlobal("EX_CONSTANT_ID") + 1
		IEex_WriteDword(effectData + 0x5C, constantID)
		IEex_SetGlobal("EX_CONSTANT_ID", constantID)
		initializing = true
	end
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local sourceX, sourceY = IEex_GetActorLocation(sourceID)
	if not IEex_IsSprite(sourceID, true) then
		sourceX = IEex_ReadDword(effectData + 0x7C)
		sourceY = IEex_ReadDword(effectData + 0x80)
	end
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	local isLarge = false
	if bit.band(savingthrow, 0x10000) > 0 then
		targetX, targetY = IEex_GetActorLocation(targetID)
		local animationData = IEex_ReadDword(creatureData + 0x50F0)
		if animationData > 0 then
			isLarge = (math.abs(IEex_ReadDword(animationData + 0x10)) >= 32)
		end
	end
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if timing == 4096 and initializing then
		if bit.band(savingthrow, 0x20000) > 0 then
			local numFrames = 0
			local resWrapper = IEex_DemandRes(visualEffectRES, "BAM")
			if resWrapper:isValid() then
				local bamData = resWrapper:getData()
				local numFrameEntries = IEex_ReadSignedWord(bamData + 0x8, 0x0)
				local frameEntriesOffset = IEex_ReadDword(bamData + 0xC)
				numFrames = IEex_ReadSignedWord(bamData + frameEntriesOffset + numFrameEntries * 0xC + visualEffectCycle * 0x4, 0x0)
			end
			resWrapper:free()
			duration = time_applied + numFrames - visualEffectBlankFrames
			IEex_WriteDword(effectData + 0x24, duration)
		end
	end
	local areaData = IEex_ReadDword(creatureData + 0x12)
	if areaData <= 0 then return end
	local areaRES = IEex_ReadLString(areaData, 8)
	local previousAreaRES = IEex_ReadLString(effectData + 0x6C, 8)
	local inactiveExists = false
	local activeExists = false
	local gotEffect = false
	if areaRES ~= previousAreaRES then
		IEex_IterateIDs(areaData, 0x31, function(currentID)
			local currentShare = IEex_GetActorShare(currentID)
			local scriptName = IEex_ReadLString(currentShare + 0x554, 32)
			if scriptName == areaRES .. "AREAGL" then
				if bit.band(savingthrow, 0x10000) == 0 then
					IEex_ApplyEffectToActor(currentID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["resource"] = visualEffectName,
["parameter2"] = 230,
["parameter3"] = constantID,
["parameter4"] = duration,
["savingthrow"] = 0x20000,
["casterlvl"] = casterlvl,
["source_x"] = sourceX,
["source_y"] = sourceY,
["source_id"] = sourceID,
})
					IEex_IterateActorEffects(currentID, function(eData)
						local theopcode = IEex_ReadDword(eData + 0x10)
						local theparameter2 = IEex_ReadDword(eData + 0x20)
						local theresource = IEex_ReadLString(eData + 0x30, 8)
						local thesavingthrow = IEex_ReadDword(eData + 0x40)
						local thesourceID = IEex_ReadDword(eData + 0x110)
						if theopcode == 288 and theparameter2 == 230 and bit.band(thesavingthrow, 0x20000) > 0 and theresource == visualEffectName and IEex_ReadDword(eData + 0x114) == 0 then
							gotEffect = true
						end
					end)
				else
					IEex_IterateActorEffects(currentID, function(eData)
						local theopcode = IEex_ReadDword(eData + 0x10)
						local theparameter2 = IEex_ReadDword(eData + 0x20)
						local theresource = IEex_ReadLString(eData + 0x30, 8)
						local thesavingthrow = IEex_ReadDword(eData + 0x40)
						local thesourceID = IEex_ReadDword(eData + 0x110)
						if theopcode == 288 and theparameter2 == 230 and bit.band(thesavingthrow, 0x40000) > 0 and theresource == visualEffectName and thesourceID == targetID and IEex_ReadDword(eData + 0x114) == 0 then
							IEex_WriteDword(eData + 0x114, 1)
						end
					end)
					IEex_ApplyEffectToActor(currentID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["resource"] = visualEffectName,
["parameter2"] = 230,
["parameter3"] = constantID,
["parameter4"] = duration,
["savingthrow"] = 0x40000,
["casterlvl"] = casterlvl,
["source_x"] = sourceX,
["source_y"] = sourceY,
["internal_flags"] = internalFlags,
["source_target"] = currentID,
["source_id"] = targetID,
})
					IEex_IterateActorEffects(currentID, function(eData)
						local theopcode = IEex_ReadDword(eData + 0x10)
						local theparameter2 = IEex_ReadDword(eData + 0x20)
						local theresource = IEex_ReadLString(eData + 0x30, 8)
						local thesavingthrow = IEex_ReadDword(eData + 0x40)
						local thesourceID = IEex_ReadDword(eData + 0x110)
						if theopcode == 288 and theparameter2 == 230 and bit.band(thesavingthrow, 0x40000) > 0 and theresource == visualEffectName and IEex_ReadDword(eData + 0x114) == 0 then
							gotEffect = true
						end
					end)
				end
			end
		end)
		if gotEffect then
			IEex_WriteLString(effectData + 0x6C, areaRES, 8)
		end
	end
	if not initializing then
		IEex_IterateIDs(areaData, 0x30, function(staticID)
			local staticData = IEex_GetActorShare(staticID)
			local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
			if scriptName == areaRES .. visualEffectName .. constantID then
				local appearanceFlags = IEex_ReadWord(staticData + 0xA2, 0x0)
				if bit.band(appearanceFlags, 0x1) > 0 then
					activeExists = true
					if bit.band(savingthrow, 0x10000) > 0 then
						IEex_WriteDword(staticData + 0x6, targetX)
						IEex_WriteDword(staticData + 0xA, targetY + 10)
						IEex_WriteWord(staticData + 0x8E, targetX)
						IEex_WriteWord(staticData + 0x90, targetY + 10)
						if (visualEffectEnlarge and visualEffectEnlarge ~= 0) or (visualEffectEnlargeOnLargeTarget and visualEffectEnlargeOnLargeTarget ~= 0 and isLarge) then
							IEex_WriteWord(staticData + 0x190, 1)
						else
							IEex_WriteWord(staticData + 0x190, 0)
						end
					end
				end
			end
		end)
	end
	
	if not activeExists and IEex_ReadDword(effectData + 0x110) == 0 then
		IEex_IterateIDs(areaData, 0x30, function(staticID)
			local staticData = IEex_GetActorShare(staticID)
			local scriptName = IEex_ReadLString(staticData + 0x6E, #(areaRES .. visualEffectName))
			if scriptName == areaRES .. visualEffectName then
				local appearanceFlags = IEex_ReadWord(staticData + 0xA2, 0x0)
				if bit.band(appearanceFlags, 0x1) == 0 then
					inactiveExists = true
					IEex_WriteLString(staticData + 0x6E, areaRES .. visualEffectName .. constantID, 32)
					IEex_WriteDword(staticData + 0x6, targetX)
					IEex_WriteDword(staticData + 0xA, targetY)
					IEex_WriteWord(staticData + 0x8E, targetX)
					IEex_WriteWord(staticData + 0x90, targetY)
					IEex_WriteWord(staticData + 0x17E, 0)
					if visualEffectCycle then
						IEex_WriteWord(staticData + 0x180, visualEffectCycle)
					end
					if (visualEffectEnlarge and visualEffectEnlarge ~= 0) or (visualEffectEnlargeOnLargeTarget and visualEffectEnlargeOnLargeTarget ~= 0 and isLarge) then
						IEex_WriteWord(staticData + 0x190, 1)
					else
						IEex_WriteWord(staticData + 0x190, 0)
					end
					IEex_WriteWord(staticData + 0xA2, bit.bor(appearanceFlags, 0x1))
					if bit.band(savingthrow, 0x10000) == 0 then
						IEex_WriteDword(effectData + 0x110, 1)
					end
				end
			end
		end)
	end
	if not inactiveExists and not activeExists and (initializing or (bit.band(savingthrow, 0x10000) > 0 and IEex_ReadDword(effectData + 0x110) == 0)) then
		IEex_CreateStatic(areaData, {
["name"] = areaRES .. visualEffectName .. constantID,
["locX"] = targetX,
["locY"] = targetY,
["locZ"] = visualEffectLocZ,
["animationResRef"] = visualEffectRES,
["appearanceFlags"] = bit.band(visualEffectFlags, 0xFFFE),
})
		IEex_IterateIDs(areaData, 0x30, function(staticID)
			local staticData = IEex_GetActorShare(staticID)
			local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
			if scriptName == areaRES .. visualEffectName .. constantID then
				IEex_WriteWord(staticData + 0x17E, 0)
				if visualEffectCycle then
					IEex_WriteWord(staticData + 0x180, visualEffectCycle)
				end
				if (visualEffectEnlarge and visualEffectEnlarge ~= 0) or (visualEffectEnlargeOnLargeTarget and visualEffectEnlargeOnLargeTarget ~= 0 and isLarge) then
					IEex_WriteWord(staticData + 0x190, 1)
				else
					IEex_WriteWord(staticData + 0x190, 0)
				end
				IEex_WriteWord(staticData + 0xA2, bit.bor(IEex_ReadWord(staticData + 0xA2, 0x0), 0x1))
			end
		end)
	end
end

ex_tornado_speed = 15
ex_current_tornado_delta = nil
function MEAREAGL(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local areaData = IEex_ReadDword(creatureData + 0x12)
	if areaData <= 0 then return end
	local areaRES = IEex_ReadLString(areaData, 8)
	local areaX = IEex_ReadDword(areaData + 0x54C)
	local areaY = IEex_ReadDword(areaData + 0x550)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local globalEffectFlags = 0
	local previousGlobalEffectFlags = IEex_ReadDword(creatureData + 0x738)
	local globalEffectInfo = {}
--[[
	for i = 0, 5, 1 do
		local partyMemberID = IEex_GetActorIDCharacter(i)
		local partyMemberShare = IEex_GetActorShare(partyMemberID)
		local timeOfDeath = IEex_ReadDword(partyMemberShare + 0x704)
		if partyMemberShare > 0 and timeOfDeath > 0 and bit.band(IEex_ReadDword(partyMemberShare + 0x5BC), 0x800) > 0 and IEex_GetActorSpellState(partyMemberID, 206) then
			local timeOfRevival = timeOfDeath + 2400 * 15
			if IEex_GetGameTick() >= timeOfRevival then
				IEex_ApplyEffectToActor(partyMemberID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
--["resist_dispel"] = 2,
["savingthrow"] = 0x20000,
["resource"] = "MERAISED",
["source_target"] = partyMemberID,
["source_id"] = partyMemberID
})
			end
		end
	end
--]]
	if not IEex_InCutsceneMode() then
		local omnivisionEnabled, specialDisableOmnivision = IEex_CheckGlobalEffectOnActor(targetID, 0x10)
		if omnivisionEnabled and not specialDisableOmnivision then
			if IEex_ReadByte(areaData + 0x86E, 0x0) ~= 255 then
				IEex_Eval('SetVisualRange(255)',targetID)
			end
		else
			if IEex_ReadByte(areaData + 0x86E, 0x0) ~= 14 then
				IEex_Eval('SetVisualRange(0)',targetID)
			end
		end
	end

	if IEex_ReadByte(creatureData + 0x758, 0x0) ~= 1 then
		IEex_WriteByte(creatureData + 0x758, 1)
		local firstGlobalStatic = ""
		for k, v in pairs(ex_global_statics) do
			firstGlobalStatic = k
			break
		end
		if firstGlobalStatic ~= "" then
			local notLoaded = true
			IEex_IterateIDs(areaData, 0x30, function(staticID)
				local staticData = IEex_GetActorShare(staticID)
				local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
				if scriptName == areaRES .. firstGlobalStatic then
					notLoaded = false
				end
			end)
			if notLoaded then
				for k, v in pairs(ex_global_statics) do
					IEex_CreateStatic(areaData, {
["name"] = areaRES .. k,
["locX"] = 0,
["locY"] = 0,
["locZ"] = v["locZ"],
["animationResRef"] = v["animationResRef"],
["appearanceFlags"] = v["appearanceFlags"],
})
				end
			end
		end
	end
	local staticsToCheck = {}
	
	local stopStatics = false
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 288 and theparameter2 == 230 and IEex_ReadDword(eData + 0x114) == 0 then
			if bit.band(thesavingthrow, 0x10000) > 0 then
				local thespecial = IEex_ReadDword(eData + 0x48)
				globalEffectFlags = bit.bor(globalEffectFlags, thespecial)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				local theorientation = IEex_ReadDword(eData + 0x60)
				local thecasterlvl = IEex_ReadDword(eData + 0xC8)
				local theinternalFlags = IEex_ReadDword(eData + 0xD8)
				local thesourceID = IEex_ReadDword(eData + 0x110)
				local thesourceX = IEex_ReadDword(eData + 0x80)
				local thesourceY = IEex_ReadDword(eData + 0x84)
				globalEffectInfo[thespecial] = {{IEex_ReadDword(eData + 0x30), IEex_ReadDword(eData + 0x34)}, thecasterlvl, theinternalFlags, thesourceID, thesourceX, thesourceY, theorientation}
	--[[
				globalEffectInfo[thespecial] = {theresource, thecasterlvl, theinternalFlags, thesourceID}
				if thespecial == 0x20000 then
					globalEffectInfo[thespecial][1] = {IEex_ReadDword(eData + 0x30), IEex_ReadDword(eData + 0x34)}
				end
	--]]
			elseif bit.band(thesavingthrow, 0x20000) > 0 then
				local constantID = IEex_ReadDword(eData + 0x60)
				local visualEffectName = IEex_ReadLString(eData + 0x30, 8)
				staticsToCheck[areaRES .. visualEffectName .. constantID] = visualEffectName
				local originalEndPoint = IEex_ReadDword(eData + 0x64)
				if IEex_GetGameTick() >= originalEndPoint and originalEndPoint ~= 0 then
					staticsToStop[areaRES .. visualEffectName .. constantID] = true
					IEex_WriteDword(eData + 0x114, 1)
				end
			elseif bit.band(thesavingthrow, 0x40000) > 0 then
				local thesourceID = IEex_ReadDword(eData + 0x110)
				local sourceShare = IEex_GetActorShare(thesourceID)
				local constantID = IEex_ReadDword(eData + 0x60)
				local visualEffectName = IEex_ReadLString(eData + 0x30, 8)
				staticsToCheck[areaRES .. visualEffectName .. constantID] = visualEffectName
				if not IEex_IsSprite(thesourceID, true) then
					staticsToStop[areaRES .. visualEffectName .. constantID] = true
					IEex_WriteDword(eData + 0x114, 1)
				else
					local foundSourceEffect = false
					IEex_IterateActorEffects(thesourceID, function(eDataB)
						local theopcodeB = IEex_ReadDword(eDataB + 0x10)
						local thetimingB = IEex_ReadDword(eDataB + 0x24)
						local thedurationB = IEex_ReadDword(eDataB + 0x28)
						local constantIDB = IEex_ReadDword(eDataB + 0x60)
						local theresourceB = IEex_ReadLString(eDataB + 0x30, 8)
						if theopcodeB == 500 and theresourceB == "EXVISEFF" and constantIDB == constantID and IEex_ReadDword(eDataB + 0x114) == 0 then
							foundSourceEffect = true
							if thetimingB == 4096 and IEex_GetGameTick() >= thedurationB then
								staticsToStop[areaRES .. visualEffectName .. constantID] = true
								IEex_WriteDword(eDataB + 0x114, 1)
							end
						end
					end)
					if not foundSourceEffect then
						staticsToStop[areaRES .. visualEffectName .. constantID] = true
						IEex_WriteDword(eData + 0x114, 1)
					end
				end
			end
		end
	end)
	IEex_IterateIDs(areaData, 0x30, function(staticID)
		local staticData = IEex_GetActorShare(staticID)
		local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
		if staticsToStop[scriptName] then
			if bit.band(IEex_ReadWord(staticData + 0xA2, 0x0), 0x1) > 0 then
--				IEex_Eval('Deactivate(\"' .. scriptName .. '\")',targetID)
				IEex_WriteWord(staticData + 0xA2, bit.band(IEex_ReadWord(staticData + 0xA2, 0x0), 0xFFFE))
			else
				staticsToStop[scriptName] = nil
			end		
			
		elseif staticsToCheck[scriptName] then
			local visualEffect = ex_custom_visual_effects[staticsToCheck[scriptName]]
			if visualEffect then
				if visualEffect["cycle"] then
					IEex_WriteWord(staticData + 0x180, visualEffect["cycle"])
				end
				if visualEffect["enlarge"] and visualEffect["enlarge"] ~= 0 then
					IEex_WriteWord(staticData + 0x190, 1)
				end
			end
		end
	end)
	IEex_WriteDword(creatureData + 0x738, globalEffectFlags)
	if bit.band(previousGlobalEffectFlags, 0x10000) > 0 and bit.band(globalEffectFlags, 0x10000) == 0 then
		IEex_Eval('Deactivate(\"' .. areaRES .. 'COFL' .. '\")',targetID)
		IEex_Eval('Deactivate(\"' .. areaRES .. 'COFR' .. '\")',targetID)
		IEex_Eval('Deactivate(\"' .. areaRES .. 'COFB' .. '\")',targetID)
		IEex_Eval('Deactivate(\"' .. areaRES .. 'COFT' .. '\")',targetID)
		IEex_IterateIDs(areaData, 0x31, function(currentID)
			local currentShare = IEex_GetActorShare(currentID)
			local scriptName = IEex_ReadLString(currentShare + 0x554, 32)
			if scriptName == "USCOFORC" then
				IEex_Eval('DestroySelf()',currentID)
			end
		end)
	end
	if bit.band(globalEffectFlags, 0x20000) > 0 then
		local targetX = 0
		local targetY = 0
		IEex_IterateIDs(areaData, 0x30, function(staticID)
			local staticData = IEex_GetActorShare(staticID)
			local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
			if scriptName == areaRES .. "TORNAD" then
				targetX = IEex_ReadDword(staticData + 0x6)
				targetY = IEex_ReadDword(staticData + 0xA)
				local searchMapWrapper = IEex_DemandRes(areaRES .. "SR", "BMP")
				local searchMapData = searchMapWrapper:getData()
				local randomWalkSpeed = ex_tornado_speed
				local deltaX = math.random(randomWalkSpeed * 2 + 1) - randomWalkSpeed - 1
				local deltaY = math.random(randomWalkSpeed * 2 + 1) - randomWalkSpeed - 1
				local finalX = targetX + deltaX
				local finalY = targetY + deltaY
				if finalX < 0 then
					finalX = 1
				elseif finalX >= areaX then
					finalX = areaX - 1
				end
				if finalY < 0 then
					finalY = 1
				elseif finalY >= areaY then
					finalY = areaY - 1
				end
				if ex_current_tornado_delta == nil or IEex_GetGameTick() % 5 == 0 then
					local currentDistance = math.floor((deltaX ^ 2 + deltaY ^ 2) ^ .5)
					local currentPixelIndex = IEex_GetBitmapPixelIndex(searchMapData, math.floor((finalX) / 16), math.floor((finalY) / 12))
					local numTries = 0
					while numTries <= 20 and (currentDistance >= randomWalkSpeed or ex_default_terrain_table_1[currentPixelIndex] == -1) do
						deltaX = math.random(randomWalkSpeed * 2 + 1) - randomWalkSpeed - 1
						deltaY = math.random(randomWalkSpeed * 2 + 1) - randomWalkSpeed - 1
						finalX = targetX + deltaX
						finalY = targetY + deltaY
						if finalX < 0 then
							finalX = 1
						elseif finalX >= areaX then
							finalX = areaX - 1
						end
						if finalY < 0 then
							finalY = 1
						elseif finalY >= areaY then
							finalY = areaY - 1
						end
						currentDistance = math.floor((deltaX ^ 2 + deltaY ^ 2) ^ .5)
						currentPixelIndex = IEex_GetBitmapPixelIndex(searchMapData, math.floor((finalX) / 16), math.floor((finalY) / 12))
						numTries = numTries + 1
					end
					ex_current_tornado_delta = {deltaX, deltaY}
				else
					deltaX = ex_current_tornado_delta[1]
					deltaY = ex_current_tornado_delta[2]
				end
				targetX = finalX
				targetY = finalY
				IEex_WriteDword(staticData + 0x6, targetX)
				IEex_WriteDword(staticData + 0xA, targetY)
				IEex_WriteWord(staticData + 0x8E, targetX)
				IEex_WriteWord(staticData + 0x90, targetY)
				IEex_WriteDword(staticData + 0x190, 1)
				searchMapWrapper:free()
			end
		end)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = globalEffectInfo[0x20000][1][1],
["parameter2"] = globalEffectInfo[0x20000][1][2],
["special"] = 160,
["savingthrow"] = 0x1010000,
["resource"] = "MEAOESP2",
["casterlvl"] = globalEffectInfo[0x20000][2],
["internal_flags"] = globalEffectInfo[0x20000][3],
["source_target"] = targetID,
["source_id"] = globalEffectInfo[0x20000][4],
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = targetX,
["target_y"] = targetY
})
	elseif bit.band(previousGlobalEffectFlags, 0x20000) > 0 then
		IEex_Eval('Deactivate(\"' .. areaRES .. 'TORNAD' .. '\")',targetID)
	end
	if bit.band(globalEffectFlags, 0x40000) > 0 then
		local targetX = 0
		local targetY = 0
		IEex_IterateIDs(areaData, 0x30, function(staticID)
			local staticData = IEex_GetActorShare(staticID)
			local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
			if scriptName == areaRES .. "GRVGLB" then
--			if scriptName == areaRES .. "GRVGL1" or scriptName == areaRES .. "GRVGL2" or scriptName == areaRES .. "GRVGL3" or scriptName == areaRES .. "GRVGL4" then
				targetX = IEex_ReadDword(staticData + 0x6)
				targetY = IEex_ReadDword(staticData + 0xA)
				IEex_WriteDword(staticData + 0x190, 1)
			end
		end)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = globalEffectInfo[0x40000][1][1],
["parameter2"] = globalEffectInfo[0x40000][1][2],
["special"] = 224,
["savingthrow"] = 0x1010000,
["resource"] = "MEAOESP2",
["casterlvl"] = globalEffectInfo[0x40000][2],
["internal_flags"] = globalEffectInfo[0x40000][3],
["source_target"] = targetID,
["source_id"] = globalEffectInfo[0x40000][4],
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = targetX,
["target_y"] = targetY
})
	elseif bit.band(previousGlobalEffectFlags, 0x40000) > 0 then
		IEex_Eval('Deactivate(\"' .. areaRES .. 'GRVGLB' .. '\")',targetID)
--		IEex_Eval('Deactivate(\"' .. areaRES .. 'GRVGL1' .. '\")',targetID)
--		IEex_Eval('Deactivate(\"' .. areaRES .. 'GRVGL2' .. '\")',targetID)
--		IEex_Eval('Deactivate(\"' .. areaRES .. 'GRVGL3' .. '\")',targetID)
--		IEex_Eval('Deactivate(\"' .. areaRES .. 'GRVGL4' .. '\")',targetID)
	end
	if bit.band(globalEffectFlags, 0x80000) > 0 then
		local targetX = 0
		local targetY = 0
		IEex_IterateIDs(areaData, 0x30, function(staticID)
			local staticData = IEex_GetActorShare(staticID)
			local scriptName = IEex_ReadLString(staticData + 0x6E, 32)
			for i = 1, 7, 1 do
				if scriptName == areaRES .. "PRISW" .. i then
				targetX = IEex_ReadDword(staticData + 0x6)
				targetY = IEex_ReadDword(staticData + 0xA)
				local orientation = globalEffectInfo[0x80000][7]
				IEex_WriteWord(staticData + 0x180, orientation)
				IEex_WriteWord(staticData + 0x190, 1)
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = 0x52505355,
["parameter2"] = 0x305349 + 0x10000 * i,
["parameter3"] = orientation,
["special"] = 0x82001E,
["savingthrow"] = 0x300000,
["resource"] = "MERECTSP",
["casterlvl"] = globalEffectInfo[0x80000][2],
["internal_flags"] = globalEffectInfo[0x80000][3],
["parent_resource"] = "USPRIS" .. i,
["source_target"] = targetID,
["source_id"] = globalEffectInfo[0x80000][4],
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = targetX,
["target_y"] = targetY
})
				end
			end
		end)
	elseif bit.band(previousGlobalEffectFlags, 0x80000) > 0 then
		for i = 1, 7, 1 do
			IEex_Eval('Deactivate(\"' .. areaRES .. 'PRISW' .. i .. '\")',targetID)
		end
	end
end

function MECRIT(effectData, creatureData)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MECRIT", 5) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if bit.band(savingthrow, 0x100000) > 0 then return end
	local matchItemType = IEex_ReadSignedWord(effectData + 0x44, 0x0)
	local totalUses = IEex_ReadSignedWord(effectData + 0x46, 0x0)
	local uses = IEex_ReadSignedWord(effectData + 0x5C, 0x0)
	if totalUses > 0 and uses >= totalUses then return end
	if matchItemType > 0 or bit.band(savingthrow, 0x70000) > 0 then
		local weaponSlot = IEex_ReadByte(creatureData + 0x4BA4, 0x0)
		local weaponHeader = IEex_ReadByte(creatureData + 0x4BA6, 0x0)
		local slotData = IEex_ReadDword(creatureData + 0x4AD8 + weaponSlot * 0x4)
		if ((weaponSlot >= 11 and weaponSlot <= 14) and bit.band(savingthrow, 0x20000) > 0) or slotData <= 0 then return end
		local weaponRES = IEex_ReadLString(slotData + 0xC, 8)
		local resWrapper = IEex_DemandRes(weaponRES, "ITM")
		if resWrapper:isValid() then
			local itemData = resWrapper:getData()
			local numHeaders = IEex_ReadSignedWord(itemData + 0x68, 0x0)
			if weaponHeader >= numHeaders then
				weaponHeader = 0
			end
			local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
			local equippedAppearance = IEex_ReadLString(itemData + 0x22, 2)
			local headerType = IEex_ReadByte(itemData + 0x82 + weaponHeader * 0x38, 0x0)
			if (bit.band(savingthrow, 0x10000) > 0 and headerType ~= 1) or (bit.band(savingthrow, 0x20000) > 0 and headerType ~= 2) or (bit.band(savingthrow, 0x40000) > 0 and (headerType ~= 1 or equippedAppearance ~= "" or (itemType ~= 0 and itemType ~= 16 and itemType ~= 19 and itemType ~= 28))) or (matchItemType > 0 and matchItemType ~= itemType) then
				resWrapper:free()
				return
			end
		end
		resWrapper:free()
	end
	IEex_WriteByte(creatureData + 0x936, IEex_ReadByte(creatureData + 0x936, 0x0) + parameter1)
	IEex_WriteByte(creatureData + 0x178E, IEex_ReadByte(creatureData + 0x178E, 0x0) + parameter1)
end

function MEAMBIDE(effectData, creatureData)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MECRIT", 5) then return end
--	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local eliminateAllPenalties = (bit.band(savingthrow, 0x10000) > 0)
	local weaponSlot = IEex_ReadByte(creatureData + 0x4BA4, 0x0)
	local rightHandPenaltyAdjust = 2
	local leftHandPenaltyAdjust = 6
	if eliminateAllPenalties then
		rightHandPenaltyAdjust = rightHandPenaltyAdjust + 4
		leftHandPenaltyAdjust = leftHandPenaltyAdjust + 4
	end
	if weaponSlot == 43 or weaponSlot == 45 or weaponSlot == 47 or weaponSlot == 49 then
		local weaponSlot = IEex_ReadByte(creatureData + 0x4BA4, 0x0)
		local weaponHeader = IEex_ReadByte(creatureData + 0x4BA6, 0x0)
		local rangerTWF = false
		local rangerLevel = IEex_ReadByte(creatureData + 0x62E, 0x0)
		if rangerLevel > 0 then
			local armorData = IEex_ReadDword(creatureData + 0x4ADC)
			if armorData > 0 then
				local armorRES = IEex_ReadLString(armorData + 0xC, 8)
				local resWrapper = IEex_DemandRes(armorRES, "ITM")
				if resWrapper:isValid() then
					local itemData = resWrapper:getData()
					local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
					if itemType == 60 or itemType == 61 or itemType == 67 then
						rangerTWF = true
					end
				end
				resWrapper:free()
			end
		end
		local offhandData = IEex_ReadDword(creatureData + 0x4AD8 + weaponSlot * 0x4 + 0x4)
		if offhandData <= 0 then return end
		local weaponRES = IEex_ReadLString(offhandData + 0xC, 8)
		local resWrapper = IEex_DemandRes(weaponRES, "ITM")
		if resWrapper:isValid() then
			local itemData = resWrapper:getData()
			local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
			if itemType == 12 or itemType == 41 or itemType == 47 or itemType == 49 or itemType == 53 then
				resWrapper:free()
				return
			elseif (itemType == 16 or itemType == 19) and eliminateAllPenalties then
				rightHandPenaltyAdjust = rightHandPenaltyAdjust - 2
				leftHandPenaltyAdjust = leftHandPenaltyAdjust - 2
			end
		end
		resWrapper:free()
		if rangerTWF or bit.band(IEex_ReadDword(creatureData + 0x75C), 0x2) > 0 then
			leftHandPenaltyAdjust = leftHandPenaltyAdjust - 4
		end
		if rangerTWF or bit.band(IEex_ReadDword(creatureData + 0x764), 0x40) > 0 then
			rightHandPenaltyAdjust = rightHandPenaltyAdjust - 2
			leftHandPenaltyAdjust = leftHandPenaltyAdjust - 2
		end
	end
	IEex_WriteByte(creatureData + 0x9F8, IEex_ReadSignedByte(creatureData + 0x9F8, 0x0) + rightHandPenaltyAdjust)
	IEex_WriteByte(creatureData + 0x9FC, IEex_ReadSignedByte(creatureData + 0x9FC, 0x0) + leftHandPenaltyAdjust)
end

ex_stat_offset = {
[1] = {0x924, 2},
[3] = {0x92E, 2},
[4] = {0x930, 2},
[5] = {0x932, 2},
[6] = {0x934, 2},
[7] = {0x938, 2},
[8] = {0x93A, 2},
[9] = {0x93C, 2},
[10] = {0x93E, 2},
[11] = {0x940, 2},
[12] = {0x96C, 1},
[14] = {0x942, 2},
[15] = {0x944, 2},
[16] = {0x946, 2},
[17] = {0x948, 2},
[18] = {0x94A, 2},
[19] = {0x94C, 2},
[20] = {0x94E, 2},
[21] = {0x950, 2},
[22] = {0x952, 2},
[23] = {0x954, 2},
[24] = {0x956, 2},
[25] = {0x964, 1},
[26] = {0x96E, 1},
[27] = {0x96D, 1},
[28] = {0x970, 1},
[29] = {0x96F, 1},
[32] = {0x95C, 2},
[33] = {0x973, 1},
[36] = {0x974, 2},
[38] = {0x976, 2},
[39] = {0x978, 2},
[40] = {0x97A, 2},
[41] = {0x97C, 2},
[42] = {0x97E, 2},
[43] = {0x980, 4},
[44] = {0x984, 4},
[50] = {0x9A6, 2},
[51] = {0x9A8, 2},
[52] = {0x9AA, 2},
[53] = {0x9AC, 2},
[54] = {0x9AE, 2},
[55] = {0x9B0, 2},
[56] = {0x9B2, 2},
[60] = {0x9D2, 2},
[71] = {0x9D4, 2},
[72] = {0x9D6, 2},
[73] = {0x9D8, 2},
[74] = {0x9DA, 2},
[75] = {0x9DC, 4},
[76] = {0x9E0, 4},
[77] = {0x9E4, 2},
[78] = {0x9E6, 2},
[79] = {0x9E8, 2},
[80] = {0x9EA, 2},
[81] = {0x9EC, 4},
[82] = {0x9F0, 4},
[83] = {0x9F4, 4},
[84] = {0x9F8, 1},
[85] = {0x9FC, 1},
[86] = {0xA00, 4},
[87] = {0xA04, 4},
[90] = {0x96A, 1},
[94] = {0x972, 1},
[95] = {0x966, 1},
[96] = {0x967, 1},
[97] = {0x968, 1},
[98] = {0x969, 1},
[99] = {0x96A, 1},
[100] = {0x96B, 1},
[101] = {0x96C, 1},
[102] = {0x96D, 1},
[103] = {0x96E, 1},
[104] = {0x96F, 1},
[105] = {0x970, 1},
[106] = {0x971, 1},
[200] = {0x5C0, 2}, --Current HP
[201] = {0x5C4, 4}, --Animation
[202] = {0x758, 1}, --Base Damage Reduction
[203] = {0x774, 1}, --Proficiency: Bow
[204] = {0x775, 1}, --Proficiency: Crossbow
[205] = {0x776, 1}, --Proficiency: Missile
[206] = {0x777, 1}, --Proficiency: Axe
[207] = {0x778, 1}, --Proficiency: Mace
[208] = {0x779, 1}, --Proficiency: Flail
[209] = {0x77A, 1}, --Proficiency: Polearm
[210] = {0x77B, 1}, --Proficiency: Hammer
[211] = {0x77C, 1}, --Proficiency: Quarterstaff
[212] = {0x77D, 1}, --Proficiency: Greatsword
[213] = {0x77E, 1}, --Proficiency: Large Sword
[214] = {0x77F, 1}, --Proficiency: Small Blade
[215] = {0x780, 1}, --Toughness
[216] = {0x781, 1}, --Armored Arcana
[217] = {0x782, 1}, --Cleave
[218] = {0x783, 1}, --Armor Proficiency
[219] = {0x784, 1}, --Spell Focus: Enhantment
[220] = {0x785, 1}, --Spell Focus: Evocation
[221] = {0x786, 1}, --Spell Focus: Necromancy
[222] = {0x787, 1}, --Spell Focus: Transmutation
[223] = {0x788, 1}, --Spell Penetration
[224] = {0x789, 1}, --Extra Rage
[225] = {0x78A, 1}, --Extra Wild Shape
[226] = {0x78B, 1}, --Extra Smiting
[227] = {0x78C, 1}, --Extra Turning
[228] = {0x78D, 1}, --Proficiency: Bastard Sword
[229] = {0xA65, 1}, --Animal Empathy
[230] = {0xA66, 1}, --Bluff
[231] = {0xA67, 1}, --Concentration
[232] = {0xA68, 1}, --Diplomacy
[233] = {0xA69, 1}, --Disable Device
[234] = {0xA6B, 1}, --Intimidate
[235] = {0xA71, 1}, --Spellcraft
[236] = {0x7F6, 1}, --Challenge Rating
[237] = {0x936, 2}, --Critical Hit Bonus
[238] = {0x926, 2}, --Armor AC Bonus
[239] = {0x928, 2}, --Deflection AC Bonus
[240] = {0x92A, 2}, --Shield AC Bonus
[241] = {0x92C, 2}, --Generic AC Bonus
[242] = {0x4C53, 1}, --Modal State
[243] = {0x4C54, 4}, --Expertise
[244] = {0x4C58, 4}, --Power Attack
[245] = {0x72EA, 1}, --Movement Speed
[246] = {0x720, 2}, --Height
[252] = {0xA60, 1}, --Mirror Images Remaining
}
function MEMODSTA(effectData, creatureData)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MECRIT", 5) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local special = IEex_ReadDword(effectData + 0x44)
	local statValue = 0x7FFFFFFF
	local bAllowEffectListCall = (IEex_ReadDword(creatureData + 0x72A4) == 1)
	if ex_stat_offset[special] ~= nil then
		if ex_stat_offset[special][2] == 1 then
			statValue = IEex_ReadSignedByte(creatureData + ex_stat_offset[special][1], 0x0)
			if parameter2 == 0 then
				statValue = statValue + parameter1
			elseif parameter2 == 1 then
				statValue = parameter1
			elseif parameter2 == 2 then
				statValue = math.floor(statValue * parameter1 / 100)
			end
--			if bAllowEffectListCall then
				IEex_WriteByte(creatureData + ex_stat_offset[special][1], statValue)
--			else
--				IEex_WriteByte(creatureData + ex_stat_offset[special][1] + 0xE58, statValue)
--			end
		elseif ex_stat_offset[special][2] == 2 then
			statValue = IEex_ReadSignedWord(creatureData + ex_stat_offset[special][1], 0x0)
			if parameter2 == 0 then
				statValue = statValue + parameter1
			elseif parameter2 == 1 then
				statValue = parameter1
			elseif parameter2 == 2 then
				statValue = math.floor(statValue * parameter1 / 100)
			end
--			if bAllowEffectListCall then
				IEex_WriteWord(creatureData + ex_stat_offset[special][1], statValue)
--			else
--				IEex_WriteWord(creatureData + ex_stat_offset[special][1] + 0xE58, statValue)
--			end
		elseif ex_stat_offset[special][2] == 4 then
			statValue = IEex_ReadDword(creatureData + ex_stat_offset[special][1])
			if parameter2 == 0 then
				statValue = statValue + parameter1
			elseif parameter2 == 1 then
				statValue = parameter1
			elseif parameter2 == 2 then
				statValue = math.floor(statValue * parameter1 / 100)
			end
--			if bAllowEffectListCall then
				IEex_WriteDword(creatureData + ex_stat_offset[special][1], statValue)
--			else
--				IEex_WriteDword(creatureData + ex_stat_offset[special][1] + 0xE58, statValue)
--			end
		end
	end
	if special >= 36 and special <= 42 and statValue <= 0 and IEex_ReadDword(creatureData + 0x12) > 0 then
		IEex_WriteDword(effectData + 0x110, 1)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 13,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 0x4,
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["source_id"] = IEex_ReadDword(effectData + 0x10C)
})
	end
end

function MEMODSKL(effectData, creatureData)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MECRIT", 5) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local special = IEex_ReadDword(effectData + 0x44)
	if special > 15 then return end
	if special >= 0 then
		if IEex_ReadSignedByte(creatureData + 0x7B4 + special, 0x0) <= 0 then
			if tonumber(IEex_2DAGetAtStrings("SKILLS", "UNTRAINED", ex_skill_name[special])) == 0 then return end
		end
		IEex_WriteByte(creatureData + 0xA64 + special, IEex_ReadSignedByte(creatureData + 0xA64 + special, 0x0) + parameter1)
	else
		for i = 0, 15, 1 do
			if IEex_ReadSignedByte(creatureData + 0x7B4 + i, 0x0) > 0 or tonumber(IEex_2DAGetAtStrings("SKILLS", "UNTRAINED", ex_skill_name[i])) == 1 then
				IEex_WriteByte(creatureData + 0xA64 + i, IEex_ReadSignedByte(creatureData + 0xA64 + i, 0x0) + parameter1)
			end
		end
	end
end
--[[
function MEMODMSL(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local maxLevel = IEex_ReadDword(effectData + 0x1C)
	if maxLevel > 9 then
		maxLevel = 9
	elseif maxLevel <= 0 then
		maxLevel = 1
	end
	local minLevel = IEex_ReadDword(effectData + 0x44)
	if minLevel > 9 then
		minLevel = 9
	elseif minLevel <= 0 then
		minLevel = 1
	end
	if maxLevel < minLevel then
		maxLevel = minLevel
	end
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local casterTypes = {}
	for i = 1, 7, 1 do
		if bit.band(savingthrow, 2 ^ (i + 15)) > 0 then
			table.insert(casterTypes, i)
		end
	end
	if bit.band(savingthrow, 0x7F0000) == 0 then
		casterTypes = {1, 2, 3, 4, 5, 6, 7}
	end
	for k, cType in ipairs(casterTypes) do
		for level = minLevel, maxLevel, 1 do
			local offset = creatureData + 0x4284 + (cType - 1) * 0x100 + (level - 1) * 0x1C
			local totalCount = IEex_ReadDword(offset + 0x14)
			local sorcererCastableCount = IEex_ReadDword(offset + 0x18)
			if totalCount > 0 or bit.band(savingthrow, 0x1000000) > 0 then
				totalCount = totalCount + parameter1
				if totalCount < 0 then
					totalCount = 0
				end
				IEex_WriteDword(offset + 0x14, totalCount)
				local currentSpell = IEex_ReadDword(offset + 0x4)
				local lastSpell = IEex_ReadDword(offset + 0x8)

				if cType == 1 or cType == 6 then
					if sorcererCastableCount > totalCount then
						IEex_WriteDword(offset + 0x18, totalCount)
					end
					while currentSpell ~= lastSpell do
						local currentMemorizedCount = IEex_ReadDword(currentSpell + 0x8)
						currentMemorizedCount = currentMemorizedCount + parameter1
						if currentMemorizedCount < 0 then
							currentMemorizedCount = 0
						end
						IEex_WriteDword(currentSpell + 0x8, currentMemorizedCount)
						currentSpell = currentSpell + 0x10

					end
				end
			end
		end
	end
end
--]]

function MEBARBDR(effectData, creatureData)
	if true then return end
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MECRIT", 5) then return end
	local barbarianLevel = IEex_GetActorStat(targetID, 96)
	local barbarianDamageResistance = math.floor((barbarianLevel + 1) / 3)
	local applyExtraResistance = false
	local slotData = IEex_ReadDword(creatureData + 0x4ADC)
	if slotData <= 0 then return end
	local armorRES = IEex_ReadLString(slotData + 0xC, 8)
	local resWrapper = IEex_DemandRes(armorRES, "ITM")
	if resWrapper:isValid() then
		local itemData = resWrapper:getData()
		local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
		if itemType == 62 or itemType == 66 or itemType == 68 then
			applyExtraResistance = true
		end
	end
	resWrapper:free()
	if not applyExtraResistance then return end
	IEex_WriteWord(creatureData + 0x950, IEex_ReadSignedWord(creatureData + 0x950, 0x0) + barbarianDamageResistance)
	IEex_WriteWord(creatureData + 0x952, IEex_ReadSignedWord(creatureData + 0x952, 0x0) + barbarianDamageResistance)
	IEex_WriteWord(creatureData + 0x954, IEex_ReadSignedWord(creatureData + 0x954, 0x0) + barbarianDamageResistance)
	IEex_WriteWord(creatureData + 0x956, IEex_ReadSignedWord(creatureData + 0x956, 0x0) + barbarianDamageResistance)
end

function MEBARBMV(effectData, creatureData)
	if true then return end
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MECRIT", 5) then return end
	local barbarianLevel = IEex_GetActorStat(targetID, 96)
	local barbarianDamageResistance = math.floor((barbarianLevel + 1) / 3)
	local applyExtraMovement = true
	local applyExtraResistance = false
	local animationData = IEex_ReadDword(creatureData + 0x50F0)
	if animationData <= 0 then return end
	local adjustedMovementRate = IEex_ReadByte(animationData + 0x7, 0x0)
	local slotData = IEex_ReadDword(creatureData + 0x4ADC)
	if slotData > 0 then
		local armorRES = IEex_ReadLString(slotData + 0xC, 8)
		local resWrapper = IEex_DemandRes(armorRES, "ITM")
		if resWrapper:isValid() then
			local itemData = resWrapper:getData()
			local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
			if itemType == 63 or itemType == 64 or itemType == 65 then
				applyExtraMovement = false
			elseif itemType == 62 or itemType == 66 or itemType == 68 then
				applyExtraResistance = true
			end
		end
		resWrapper:free()
	end
	if IEex_ReadByte(creatureData + 0x9D4, 0x0) > 0 then
		applyExtraMovement = false
	end
	if adjustedMovementRate ~= 0 then
		if applyExtraMovement then
			adjustedMovementRate = adjustedMovementRate + 2
			if adjustedMovementRate > 255 then
				adjustedMovementRate = 255
			end
		else
			adjustedMovementRate = adjustedMovementRate - 1
		end
		IEex_WriteByte(animationData + 0x7, adjustedMovementRate)
	end
	IEex_WriteWord(creatureData + 0x956, IEex_ReadSignedWord(creatureData + 0x956, 0x0) - barbarianDamageResistance)
	if applyExtraResistance then
		IEex_WriteWord(creatureData + 0x950, IEex_ReadSignedWord(creatureData + 0x950, 0x0) + barbarianDamageResistance)
		IEex_WriteWord(creatureData + 0x952, IEex_ReadSignedWord(creatureData + 0x952, 0x0) + barbarianDamageResistance)
		IEex_WriteWord(creatureData + 0x954, IEex_ReadSignedWord(creatureData + 0x954, 0x0) + barbarianDamageResistance)
--		IEex_WriteWord(creatureData + 0x956, IEex_ReadSignedWord(creatureData + 0x956, 0x0) + barbarianDamageResistance)
	end
end

--[[
function IEex_EvaluatePersistentEffects(actorID)
	if not IEex_IsSprite(actorID, false) then return end
	local creatureData = IEex_GetActorShare(actorID)
	local tick = IEex_GetGameTick()
	local previousTick = ex_last_evaluation_tick[actorID]
	if previousTick == nil or tick ~= previousTick then
		ex_last_evaluation_tick[actorID] = tick
--	local temporaryFlags = IEex_ReadWord(creatureData + 0x9FA, 0x0)
--	if bit.band(temporaryFlags, 0x1) == 0 then
--		IEex_WriteWord(creatureData + 0x9FA, bit.bor(temporaryFlags, 0x1))
		local persistentEffectsList = {}

		IEex_IterateActorEffects(actorID, function(eData)
			local theperiod = 1
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thetime_applied = IEex_ReadDword(eData + 0x68)
			local newopcode = 402
			local newparameter1 = 1
			local newparameter2 = 0
			local addEffect = false
			if theopcode == 25 or theopcode == 98 then
				addEffect = true
				if theopcode == 25 then
					newopcode = 12
					newparameter2 = 0x200000
				elseif theopcode == 98 then
					newopcode = 17
				end
				if theparameter2 == 1 or theparameter2 == 2 or theparameter2 == 4 then
					newparameter1 = theparameter1
				end
				if theparameter2 == 3 then
					theperiod = theparameter1
				elseif theparameter2 == 4 then
					theperiod = 7
				end
			end
			if theopcode == 434 then
				addEffect = true
				newparameter1 = 0
				theperiod = theparameter1
			end

			if addEffect and (tick - thetime_applied) % (theperiod * 15) == 0 and (tick > thetime_applied + 1 or theopcode == 434) then
				table.insert(persistentEffectsList, {
["opcode"] = newopcode,
["parameter1"] = newparameter1,
["parameter2"] = newparameter2,
["resource"] = theresource,
["parent_resource"] = IEex_ReadLString(eData + 0x94, 8),
["casterlvl"] = IEex_ReadDword(eData + 0xC8),
["source_id"] = IEex_ReadDword(eData + 0x110),
})
			end
		end)
		for k, effect in ipairs(persistentEffectsList) do
			IEex_ApplyEffectToActor(actorID, {
["opcode"] = effect["opcode"],
["target"] = 2,
["parameter1"] = effect["parameter1"],
["parameter2"] = effect["parameter2"],
["timing"] = 1,
["resource"] = effect["resource"],
["parent_resource"] = effect["parent_resource"],
["casterlvl"] = effect["casterlvl"],
["source_id"] = effect["source_id"],
})
		end
		local repermCounter = IEex_ReadSignedByte(creatureData + 0x731, 0x0)
		if repermCounter == -1 then
			repermCounter = 0
		end
		repermCounter = repermCounter + 1
		if repermCounter >= 15 then
			repermCounter = 0
			IEex_WriteByte(creatureData + 0x731, repermCounter)
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["resource"] = "MEREPERM",
["source_id"] = sourceID
})
		else
			IEex_WriteByte(creatureData + 0x731, repermCounter)
		end
	end
end
--]]

function MEPANIC(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	if (actionID == 24 or actionID == 85) and IEex_GetActorState(sourceID, 0x4) then
		local ids = {}
		if IEex_ReadDword(creatureData + 0x12) > 0 then
			ids = IEex_GetIDArea(sourceID, 0x31)
		end
		local sourceX, sourceY = IEex_GetActorLocation(sourceID)
		local closestDistance = 0x7FFFFFFF
		local targetID = -1
		for k, currentID in ipairs(ids) do
			local currentShare = IEex_GetActorShare(currentID)
			if currentShare > 0 then
				local currentX = IEex_ReadDword(currentShare + 0x6)
				local currentY = IEex_ReadDword(currentShare + 0xA)
				local currentDistance = IEex_GetDistanceIsometric(sourceX, sourceY, currentX, currentY)
				local states = IEex_ReadDword(currentShare + 0x5BC)
				local cea = IEex_CompareActorAllegiances(sourceID, currentID)
				if currentDistance < closestDistance and cea == -1 and IEex_CheckActorLOSObject(sourceID, currentID) and bit.band(states, 0x800) == 0 and IEex_ReadByte(currentShare + 0x838, 0x0) == 0 then
						closestDistance = currentDistance
						targetID = currentID
				end
			end
		end
		if targetID > 0 then
			IEex_SetActionID(actionData, 184)
			IEex_WriteDword(creatureData + 0x4BE, targetID)
			IEex_WriteDword(creatureData + 0x52C, 100)
			IEex_WriteDword(creatureData + 0x530, 100)
			IEex_WriteDword(creatureData + 0x534, 100)
		end
	end
end

IEex_AddActionHookGlobal("MEPANIC")

ex_item_use_resource = {}

function MEITMUSE(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	if (actionID == 34) and IEex_IsPartyMember(sourceID) then
		local itemSlot = IEex_GetActionInt1(actionData)
		if itemSlot >= 0 and itemSlot <= 50 then
			local slotData = IEex_ReadDword(creatureData + 0x4AD8 + itemSlot * 0x4)
			if slotData > 0 then
				ex_item_use_resource[sourceID] = IEex_ReadLString(slotData + 0xC, 0x8)
			end
		end
	end
end

IEex_AddActionHookGlobal("MEITMUSE")

function MESPLOPP(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	if actionID == 31 or actionID == 95 or actionID == 113 or actionID == 114 or actionID == 191 or actionID == 192 then
		local spellRES = IEex_GetActorSpellRES(sourceID)
		local provokeAttackOfOpportunity = true
		if spellRES ~= "" then
			local isSpell = (ex_listspll[spellRES] ~= nil or ex_true_spell[spellRES] ~= nil)
			if not isSpell then
				provokeAttackOfOpportunity = false
			end
			local resWrapper = IEex_DemandRes(spellRES, "SPL")
			local targetID = IEex_ReadDword(creatureData + 0x4BE)
			if resWrapper:isValid() then
				local spellData = resWrapper:getData()
				local spellFlags = IEex_ReadDword(spellData + 0x18)
				if bit.band(spellFlags, 0x1000000) > 0 then
					if isSpell then
						provokeAttackOfOpportunity = false
					else
						provokeAttackOfOpportunity = true
					end
				end
				if bit.band(spellFlags, 0x2000000) > 0 and IEex_IsSprite(targetID, false) and IEex_CompareActorAllegiances(sourceID, targetID) == -1 then
					provokeAttackOfOpportunity = false
				end
				local castingTime = IEex_ReadSignedWord(spellData + 0x94, 0x0) - IEex_GetActorStat(sourceID, 77)
				if castingTime <= 0 then
					provokeAttackOfOpportunity = false
				end
			end
			resWrapper:free()
		end
		if provokeAttackOfOpportunity then
			ex_attopp_casting[sourceID] = {}
		else
			ex_attopp_casting[sourceID] = nil
		end
	end
end

IEex_AddActionHookGlobal("MESPLOPP")


ex_superfast_attack_cut = {
[16] = {1, 1, 1, 1, 1, 1, 1},
[17] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
[18] = {2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
[19] = {2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
[20] = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1},
[21] = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1},
[22] = {3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
[23] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
[24] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
[25] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2},
[26] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2},
[27] = {4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
[28] = {4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
[29] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
[30] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
[31] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
[32] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
[33] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3},
[34] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3},
[35] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3},
[36] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[37] = {5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[38] = {5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[39] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[40] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[41] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[42] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[43] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[44] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[45] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[46] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[47] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[48] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[49] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
[50] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
}
ex_attopp_count = {}
ex_attopp_timer = {}
ex_attopp_repeat_timer = {}
ex_attopp_casting = {}
ex_attopp_target = {}
ex_attopp_range = {}
ex_attopp_opportunist = {}

function IEex_CheckMonkAttackBonus(creatureData)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local fixMonkAttackBonus = false
	local monkAttackBonusDisabled = false
	local monkLevel = IEex_GetActorStat(targetID, 101)
	if monkLevel > 0 then
		fixMonkAttackBonus = true
		if IEex_GetActorStat(targetID, 96) > 0 or IEex_GetActorStat(targetID, 97) > 0 or IEex_GetActorStat(targetID, 98) > 0 or IEex_GetActorStat(targetID, 99) > 0 or IEex_GetActorStat(targetID, 100) > 0 or IEex_GetActorStat(targetID, 102) > 0 or IEex_GetActorStat(targetID, 103) > 0 or IEex_GetActorStat(targetID, 104) > 0 or IEex_GetActorStat(targetID, 105) > 1 or IEex_GetActorStat(targetID, 106) > 1 then
			monkAttackBonusDisabled = true
		end
		if IEex_ReadByte(creatureData + 0x4BA4, 0x0) ~= 10 then
			monkAttackBonusDisabled = true
		end
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if theopcode == 288 and theparameter2 == 241 then
				local thegeneralitemcategory = IEex_ReadByte(eData + 0x48, 0x0)
				if thegeneralitemcategory ~= 6 then
					monkAttackBonusDisabled = true
					if (thegeneralitemcategory == 1 and (theparameter1 ~= 67 or not ex_elven_chainmail_counts_as_unarmored)) or thegeneralitemcategory == 3 or (thegeneralitemcategory >= 4 and ex_special_monk_weapon_types[theparameter1] == nil) then
						fixMonkAttackBonus = false
					end
				end
			end
		end)
	end
	return monkAttackBonusDisabled, fixMonkAttackBonus
end

function IEex_CheckMonkACBonus(creatureData)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local fixMonkACBonus = false
	local monkACBonusDisabled = false
	local monkLevel = IEex_GetActorStat(targetID, 101)
	if monkLevel > 0 then
		fixMonkACBonus = true
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if theopcode == 288 and theparameter2 == 241 then
				local thegeneralitemcategory = IEex_ReadByte(eData + 0x48, 0x0)
				if thegeneralitemcategory >= 1 and thegeneralitemcategory <= 3 then
					monkACBonusDisabled = true
					if (thegeneralitemcategory == 1 and (theparameter1 ~= 67 or not ex_elven_chainmail_counts_as_unarmored)) or thegeneralitemcategory == 3 then
						fixMonkACBonus = false
					end
				end
			elseif theopcode == 502 and theresource == "MEPOLYBL" then
				if thespecial > monkLevel then
					fixMonkACBonus = false
				end
			end
		end)
	end
	if IEex_ReadByte(creatureData + 0x9D4, 0x0) > 0 then
		fixMonkACBonus = false
	end
	return monkACBonusDisabled, fixMonkACBonus
end

function IEex_IncrementAnimationFrame(creatureData, value)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local animationData = IEex_ReadDword(creatureData + 0x50F0)
	local sequence = IEex_ReadDword(creatureData + 0x50F4)
	if sequence == 0 or sequence == 8 or sequence == 11 then
		local animationFrame = IEex_ReadSignedWord(animationData + 0x694, 0x0)
		IEex_WriteWord(animationData + 0x694, animationFrame + value)
		IEex_WriteWord(animationData + 0xA2C, animationFrame + value)
		IEex_WriteWord(animationData + 0xDC4, animationFrame + value)
		IEex_WriteWord(animationData + 0x1236, animationFrame + value)
	elseif sequence == 12 then
		local animationFrame = IEex_ReadSignedWord(animationData + 0x76E, 0x0)
		IEex_WriteWord(animationData + 0x76E, animationFrame + value)
		IEex_WriteWord(animationData + 0xB06, animationFrame + value)
		IEex_WriteWord(animationData + 0xE9E, animationFrame + value)
		IEex_WriteWord(animationData + 0x1310, animationFrame + value)
	elseif sequence == 13 then
		local animationFrame = IEex_ReadSignedWord(animationData + 0x848, 0x0)
		IEex_WriteWord(animationData + 0x848, animationFrame + value)
		IEex_WriteWord(animationData + 0xBE0, animationFrame + value)
		IEex_WriteWord(animationData + 0xF78, animationFrame + value)
		IEex_WriteWord(animationData + 0x13EA, animationFrame + value)
	elseif sequence == 2 or sequence == 3 then
		local animationFrame = IEex_ReadSignedWord(animationData + 0x5BA, 0x0)
		IEex_WriteWord(animationData + 0x5BA, animationFrame + value)
		IEex_WriteWord(animationData + 0x115C, animationFrame + value)
	else
		local animationFrame = IEex_ReadSignedWord(animationData + 0x4E0, 0x0)
		IEex_WriteWord(animationData + 0x4E0, animationFrame + value)
		IEex_WriteWord(animationData + 0x952, animationFrame + value)
		IEex_WriteWord(animationData + 0xCEA, animationFrame + value)
		IEex_WriteWord(animationData + 0x1082, animationFrame + value)
	end
end

function IEex_GetAttackAnimationFrame(creatureData)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local animationData = IEex_ReadDword(creatureData + 0x50F0)
	local animationID = IEex_ReadWord(animationData + 0x4, 0x0)
	local sequence = IEex_ReadDword(creatureData + 0x50F4)
	if sequence == 0 or sequence == 8 or sequence == 11 or sequence == 12 or sequence == 13 then
		local vidcellList = {}
		if animationID >= 0x5000 and animationID <= 0x6FFF then
			return IEex_ReadSignedWord(animationData + 0x694, 0x0)
		elseif animationID >= 0x7000 and animationID <= 0x7EFF then
			vidcellList = ex_animation_vidcells[0x7000]
		elseif animationID >= 0x7F00 and animationID <= 0x7FFF then
			vidcellList = ex_animation_vidcells[0x7F00]
		elseif animationID >= 0x8000 and animationID <= 0x8FFF then
			vidcellList = ex_animation_vidcells[0x8000]
		elseif animationID >= 0xE000 and animationID <= 0xEFFF then
			vidcellList = ex_animation_vidcells[0xE000]
		elseif animationID >= 0xF000 and animationID <= 0xFFFF then
			vidcellList = ex_animation_vidcells[0xF000]
		end
		if #vidcellList > 0 then
			for k, v in ipairs(vidcellList) do
--				IEex_WriteWord(animationData + v + 0xC4, value)
			end
		end
	end
--[[
	if sequence == 0 or sequence == 8 or sequence == 11 then
		IEex_WriteWord(animationData + 0x694, value)
		IEex_WriteWord(animationData + 0xA2C, value)
		IEex_WriteWord(animationData + 0xDC4, value)
		IEex_WriteWord(animationData + 0x1236, value)
	elseif sequence == 12 then
		IEex_WriteWord(animationData + 0x76E, value)
		IEex_WriteWord(animationData + 0xB06, value)
		IEex_WriteWord(animationData + 0xE9E, value)
		IEex_WriteWord(animationData + 0x1310, value)
	elseif sequence == 13 then
		IEex_WriteWord(animationData + 0x848, value)
		IEex_WriteWord(animationData + 0xBE0, value)
		IEex_WriteWord(animationData + 0xF78, value)
		IEex_WriteWord(animationData + 0x13EA, value)
	end
--]]
	return 0
end

function IEex_SetAttackAnimationFrame(creatureData, value)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local animationData = IEex_ReadDword(creatureData + 0x50F0)
	local animationID = IEex_ReadWord(animationData + 0x4, 0x0)
	local sequence = IEex_ReadDword(creatureData + 0x50F4)
	if sequence == 0 or sequence == 8 or sequence == 11 or sequence == 12 or sequence == 13 then
		local vidcellList = {}
		if animationID >= 0x5000 and animationID <= 0x6FFF then
			vidcellList = ex_animation_vidcells[0x5000]
		elseif animationID >= 0x7000 and animationID <= 0x7EFF then
			vidcellList = ex_animation_vidcells[0x7000]
		elseif animationID >= 0x7F00 and animationID <= 0x7FFF then
			vidcellList = ex_animation_vidcells[0x7F00]
		elseif animationID >= 0x8000 and animationID <= 0x8FFF then
			vidcellList = ex_animation_vidcells[0x8000]
		elseif animationID >= 0xE000 and animationID <= 0xEFFF then
			vidcellList = ex_animation_vidcells[0xE000]
		elseif animationID >= 0xF000 and animationID <= 0xFFFF then
			vidcellList = ex_animation_vidcells[0xF000]
		end
		if #vidcellList > 0 then
			for k, v in ipairs(vidcellList) do
				IEex_WriteWord(animationData + v + 0xC4, value)
			end
		end
	end
--[[
	if sequence == 0 or sequence == 8 or sequence == 11 then
		IEex_WriteWord(animationData + 0x694, value)
		IEex_WriteWord(animationData + 0xA2C, value)
		IEex_WriteWord(animationData + 0xDC4, value)
		IEex_WriteWord(animationData + 0x1236, value)
	elseif sequence == 12 then
		IEex_WriteWord(animationData + 0x76E, value)
		IEex_WriteWord(animationData + 0xB06, value)
		IEex_WriteWord(animationData + 0xE9E, value)
		IEex_WriteWord(animationData + 0x1310, value)
	elseif sequence == 13 then
		IEex_WriteWord(animationData + 0x848, value)
		IEex_WriteWord(animationData + 0xBE0, value)
		IEex_WriteWord(animationData + 0xF78, value)
		IEex_WriteWord(animationData + 0x13EA, value)
	end
--]]
end

function MECOPYEQ(effectData, creatureData)
	if true then return end
end

function MESETAPR(effectData, creatureData)
	if true then return end
end

ex_class_name = {"BARBARIAN", "BARD", "CLERIC", "DRUID", "FIGHTER", "MONK", "PALADIN", "RANGER", "ROGUE", "SORCERER", "WIZARD"}

function MEAPRBON(effectData, creatureData)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MEAPRBON", 5) then return end
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
--[[
	if bit.band(savingthrow, 0x10000000) == 0 then
		savingthrow = bit.bor(savingthrow, 0x10000000)
		IEex_WriteDword(effectData + 0x3C, savingthrow)
		local allBlank = true
		for i = 1, 9, 1 do
			if IEex_ReadDword(creatureData + 0x3D10 + i * 0x4) ~= 100 then
				allBlank = false
			end
		end
		if allBlank then
			local class = 1
			for i = 1, 11, 1 do
				if IEex_GetActorStat(targetID, 95 + i) > 0 then
					class = i
				end
			end
			local classString = ex_class_name[class]
			for i = 1, 9, 1 do
				IEex_WriteDword(creatureData + 0x3D10 + i * 0x4, tonumber(IEex_2DAGetAtStrings("QSLOTS", "SLOT" .. i, classString)))
			end
		end
	end
--]]
	local setAPR = 65535
	local finalSetAPR = 65535
	local bonusAPR = 0
	local baseCriticalHitImmunity = IEex_ReadSignedByte(creatureData + 0x70A, 0x0)
	local criticalHitImmunity = baseCriticalHitImmunity
	local doubleExpertise = false
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter1 = IEex_ReadDword(eData + 0x1C)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 1 and theparameter2 == 0 then
			bonusAPR = bonusAPR + theparameter1
		elseif theopcode == 500 then
			if theresource == "MESETAPR" then
				if bit.band(thesavingthrow, 0x10000) > 0 then
					finalSetAPR = theparameter1
				else
					setAPR = theparameter1
					if bit.band(thesavingthrow, 0x20000) > 0 and ex_feat_name_id["ME_RAPID_RELOAD"] ~= nil then
						setAPR = setAPR + IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_RAPID_RELOAD"], 0x0)
					end
				end
			elseif theresource == "MECRITIM" and baseCriticalHitImmunity ~= -1 then
				if bit.band(thesavingthrow, 0x10000) > 0 then
					criticalHitImmunity = criticalHitImmunity - 1
				else
					criticalHitImmunity = criticalHitImmunity + 1
				end
			end
		elseif theopcode == 0 and bit.band(thesavingthrow, 0x40000) > 0 then
			doubleExpertise = true
		end
	end)
	local expertiseCount = IEex_ReadDword(creatureData + 0x4C54)
	if expertiseCount > 0 then
		local actionID = IEex_ReadWord(creatureData + 0x476, 0x0)
		local isRanged = false
		local weaponSlot = IEex_ReadByte(creatureData + 0x4BA4, 0x0)
		local weaponHeader = IEex_ReadByte(creatureData + 0x4BA6, 0x0)
		local weaponRES = ""
		local slotData = IEex_ReadDword(creatureData + 0x4AD8 + weaponSlot * 0x4)
		local weaponWrapper = 0
		if slotData > 0 then
			weaponRES = IEex_ReadLString(slotData + 0xC, 8)
			weaponWrapper = IEex_DemandRes(weaponRES, "ITM")
			if weaponWrapper:isValid() then
				local itemData = weaponWrapper:getData()
				local numHeaders = IEex_ReadSignedWord(itemData + 0x68, 0x0)
				if weaponHeader >= numHeaders then
					weaponHeader = 0
				end
				headerType = IEex_ReadByte(itemData + 0x82 + weaponHeader * 0x38, 0x0)
				local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
				if headerType == 2 then
					isRanged = true
				end
			end
			weaponWrapper:free()
		end
		if not isRanged then
			if actionID ~= 3 and actionID ~= 94 and actionID ~= 98 and actionID ~= 105 and actionID ~= 134 and actionID ~= 27 then
				IEex_WriteWord(creatureData + 0x92C, IEex_ReadSignedWord(creatureData + 0x92C, 0x0) - expertiseCount)
			elseif doubleExpertise then
				IEex_WriteWord(creatureData + 0x92C, IEex_ReadSignedWord(creatureData + 0x92C, 0x0) + expertiseCount)
			end
			if doubleExpertise then
				IEex_WriteWord(creatureData + 0x938, IEex_ReadSignedWord(creatureData + 0x938, 0x0) - expertiseCount)
			end
		end
	end
	if baseCriticalHitImmunity ~= -1 then
		local specialFlags = IEex_ReadByte(creatureData + 0x89F, 0x0)
		if criticalHitImmunity >= 1 then
			IEex_WriteByte(creatureData + 0x89F, bit.bor(specialFlags, 0x2))
		else
			IEex_WriteByte(creatureData + 0x89F, bit.band(specialFlags, 0xFD))
		end
	end
	if setAPR ~= 65535 then
		setAPR = setAPR + bonusAPR
		if setAPR < 0 then
			setAPR = 0
		elseif setAPR > 5 then
			setAPR = 5
		end
		IEex_WriteWord(creatureData + 0x93A, setAPR)
	end
	IEex_ApplyStatScaling(targetID)
	local armorType = 67
	if ex_feat_name_id["ME_LIGHT_ARMOR_MASTERY"] ~= nil then
		local lightArmorMasteryFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_LIGHT_ARMOR_MASTERY"], 0x0)
		if lightArmorMasteryFeatCount > 0 and IEex_GetActorSpellState(targetID, 241) then
			IEex_IterateActorEffects(targetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				if theopcode == 288 and theparameter2 == 241 then
					if theparameter1 >= 60 and theparameter1 <= 68 then
						armorType = theparameter1
					end
				end
			end)
			local bAllowEffectListCall = (IEex_ReadDword(creatureData + 0x72A4) == 1)
			local dexterityBonus = math.floor((IEex_GetActorFullStat(targetID, 40) - 10) / 2)
--			local dexterityBonus = math.floor((IEex_ReadSignedWord(creatureData + 0x97A, 0x0) - 10) / 2)
			local dexterityAdjust = 0
			local maxDexBonus = 99
			local armorCheckPenalty = 0
			if ex_armor_penalties[armorType] ~= nil then
				maxDexBonus = ex_armor_penalties[armorType][2]
				armorCheckPenalty = ex_armor_penalties[armorType][3]
				if dexterityBonus > maxDexBonus then
					dexterityAdjust = dexterityBonus - maxDexBonus
				end
			end
			if armorType == 60 or armorType == 61 then
				if armorCheckPenalty > 0 then
--					if bAllowEffectListCall then
						IEex_WriteByte(creatureData + 0xA6A, IEex_ReadSignedByte(creatureData + 0xA6A, 0x0) + armorCheckPenalty + dexterityAdjust)
						IEex_WriteByte(creatureData + 0xA6D, IEex_ReadSignedByte(creatureData + 0xA6D, 0x0) + armorCheckPenalty + dexterityAdjust)
						IEex_WriteByte(creatureData + 0xA6F, IEex_ReadSignedByte(creatureData + 0xA6F, 0x0) + armorCheckPenalty + dexterityAdjust)
--					else
--						IEex_WriteByte(creatureData + 0xA6A + 0xE58, IEex_ReadSignedByte(creatureData + 0xA6A + 0xE58, 0x0) + armorCheckPenalty + dexterityAdjust)
--						IEex_WriteByte(creatureData + 0xA6D + 0xE58, IEex_ReadSignedByte(creatureData + 0xA6D + 0xE58, 0x0) + armorCheckPenalty + dexterityAdjust)
--						IEex_WriteByte(creatureData + 0xA6F + 0xE58, IEex_ReadSignedByte(creatureData + 0xA6F + 0xE58, 0x0) + armorCheckPenalty + dexterityAdjust)
--					end
				end
				if dexterityAdjust > 0 then
--					if bAllowEffectListCall then
						IEex_WriteWord(creatureData + 0x92C, IEex_ReadSignedWord(creatureData + 0x92C, 0x0) + dexterityAdjust)
--					else
--						IEex_WriteWord(creatureData + 0x92C + 0xE58, IEex_ReadSignedWord(creatureData + 0x92C + 0xE58, 0x0) + dexterityAdjust)
--					end
				end
			end
		end
	end
	local paladinLevel = IEex_ReadByte(creatureData + 0x62D, 0x0)
	if paladinLevel > 0 and paladinLevel < ex_paladin_charisma_save_bonus_level then
		local charismaModifier = math.floor((IEex_GetActorStat(targetID, 42) - 10) / 2)
		if charismaModifier > 0 then
			IEex_WriteWord(creatureData + 0x93C, IEex_ReadSignedWord(creatureData + 0x93C, 0x0) - charismaModifier)
			IEex_WriteWord(creatureData + 0x93E, IEex_ReadSignedWord(creatureData + 0x93E, 0x0) - charismaModifier)
			IEex_WriteWord(creatureData + 0x940, IEex_ReadSignedWord(creatureData + 0x940, 0x0) - charismaModifier)
		end
	end
	local baseAPR = IEex_ReadByte(creatureData + 0x5ED, 0x0)
	local animationData = IEex_ReadDword(creatureData + 0x50F0)
	if animationData <= 0 then return end
	local movementRate = IEex_ReadByte(animationData + 0x6, 0x0)
	local extraSpellResistance = IEex_GetActorStat(targetID, 95) - ex_innate_spell_resistance_cap
	if extraSpellResistance > 0 then
		local race = IEex_ReadByte(creatureData + 0x26, 0x0)
		local subrace = IEex_GetActorStat(targetID, 93)
		if (race == 2 or race == 6) and subrace == 1 then
			local spellResistance = IEex_ReadWord(creatureData + 0x94A, 0x0)
			IEex_WriteWord(creatureData + 0x94A, spellResistance - extraSpellResistance)
		end
	end
	local barbarianLevel = IEex_GetActorStat(targetID, 96)
	local monkLevel = IEex_GetActorStat(targetID, 101)
	if barbarianLevel > 0 then
		local barbarianDamageResistance = math.floor((barbarianLevel + 1) / 3)
		local applyExtraMovement = true
		local applyExtraResistance = false
		local slotData = IEex_ReadDword(creatureData + 0x4ADC)
		if slotData > 0 then
			local armorRES = IEex_ReadLString(slotData + 0xC, 8)
			local resWrapper = IEex_DemandRes(armorRES, "ITM")
			if resWrapper:isValid() then
				local itemData = resWrapper:getData()
				local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
				if itemType == 63 or itemType == 64 or itemType == 65 then
					applyExtraMovement = false
				elseif itemType == 62 or itemType == 66 or itemType == 68 then
					applyExtraResistance = true
				end
			end
			resWrapper:free()
		end
		if applyExtraMovement then
			movementRate = movementRate + 3
		end
		IEex_WriteWord(creatureData + 0x956, IEex_ReadSignedWord(creatureData + 0x956, 0x0) - barbarianDamageResistance)
		if applyExtraResistance then
			IEex_WriteWord(creatureData + 0x950, IEex_ReadSignedWord(creatureData + 0x950, 0x0) + barbarianDamageResistance)
			IEex_WriteWord(creatureData + 0x952, IEex_ReadSignedWord(creatureData + 0x952, 0x0) + barbarianDamageResistance)
			IEex_WriteWord(creatureData + 0x954, IEex_ReadSignedWord(creatureData + 0x954, 0x0) + barbarianDamageResistance)
--			IEex_WriteWord(creatureData + 0x956, IEex_ReadSignedWord(creatureData + 0x956, 0x0) + barbarianDamageResistance)
		end
	end
	if monkLevel > 0 then
--		if baseAPR < 4 then
			local monkAttackBonusDisabled, fixMonkAttackBonus = IEex_CheckMonkAttackBonus(creatureData)
			local trueBaseAPR = tonumber(IEex_2DAGetAtStrings("BAATMKU", "NUM_ATTACKS", tostring(monkLevel)))
			baseAPR = math.floor((IEex_GetActorBaseAttackBonus(targetID, false) - 1) / 5) + 1
			if baseAPR > 4 then
				baseAPR = 4
			end
			if trueBaseAPR > 4 then
				trueBaseAPR = 4
			end
			if trueBaseAPR < baseAPR then
				trueBaseAPR = baseAPR
			end
			if monkAttackBonusDisabled and fixMonkAttackBonus then
				if trueBaseAPR > baseAPR then
					IEex_WriteByte(creatureData + 0x5ED, trueBaseAPR)
				end
			elseif monkAttackBonusDisabled and not fixMonkAttackBonus then
				IEex_WriteByte(creatureData + 0x5ED, baseAPR)
			end
			local trueAPR = trueBaseAPR
			local weaponSlot = IEex_ReadByte(creatureData + 0x4BA4, 0x0)
			local weaponHeader = IEex_ReadByte(creatureData + 0x4BA6, 0x0)
			local slotData = IEex_ReadDword(creatureData + 0x4AD8 + weaponSlot * 0x4)
			local rapidShotEnabled = (IEex_ReadByte(creatureData + 0x4C64, 0x0) > 0)

			if slotData > 0 then
				local weaponRES = IEex_ReadLString(slotData + 0xC, 8)
				if fixMonkAttackBonus or not monkAttackBonusDisabled then
					trueAPR = trueAPR + ex_monk_apr_progression[monkLevel]
					if weaponRES == ex_monk_fist_progression[monkLevel] or weaponRES == ex_incorporeal_monk_fist_progression[monkLevel] or string.sub(weaponRES, 1, 7) == "00MFIST" then
						trueAPR = trueAPR + 1
					end
				else
					trueAPR = baseAPR
				end
				if weaponSlot ~= 10 and rapidShotEnabled then
					local resWrapper = IEex_DemandRes(weaponRES, "ITM")
					if resWrapper:isValid() then
						local itemData = resWrapper:getData()
						local numHeaders = IEex_ReadSignedWord(itemData + 0x68, 0x0)
						if weaponHeader >= numHeaders then
							weaponHeader = 0
						end
						local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
						headerType = IEex_ReadByte(itemData + 0x82 + weaponHeader * 0x38, 0x0)
						if rapidShotEnabled and headerType == 2 and itemType ~= 27 and itemType ~= 31 then
							trueAPR = trueAPR + 1
						end
					end
					resWrapper:free()
				end

			end
			local numWeapons = 0
			IEex_IterateActorEffects(targetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				local thespecial = IEex_ReadDword(eData + 0x48)
				if theopcode == 1 then
					if theparameter2 == 0 then
						trueAPR = trueAPR + theparameter1
					elseif theparameter2 == 1 then
						trueAPR = theparameter1
					elseif theparameter2 == 1 then
						trueAPR = math.floor(trueAPR * theparameter1 / 100)
					end
				elseif theopcode == 288 and theparameter2 == 241 then
					local thegeneralitemcategory = IEex_ReadByte(eData + 0x48, 0x0)
					if thegeneralitemcategory == 5 then
						numWeapons = numWeapons + 1
					end
				end
			end)
			local imptwfFeatCount = 0
			if ex_feat_name_id["ME_IMPROVED_TWO_WEAPON_FIGHTING"] ~= nil then
				imptwfFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_IMPROVED_TWO_WEAPON_FIGHTING"], 0x0)
			end
			local usingImptwf = false
			if numWeapons >= 2 then
				trueAPR = trueAPR + 1
				if imptwfFeatCount > 0 and (IEex_GetActorStat(targetID, 103) < 9 or wearingLightArmor or (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 16 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x2) > 0 and bit.band(IEex_ReadDword(creatureData + 0x764), 0x40) > 0)) then
					trueAPR = trueAPR + 1
					usingImptwf = true
					if imptwfFeatCount > 1 and (IEex_GetActorStat(targetID, 103) < 14 or wearingLightArmor or (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 21 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x2) > 0 and bit.band(IEex_ReadDword(creatureData + 0x764), 0x40) > 0)) then
						trueAPR = trueAPR + 1
					end
				end
			end
			if IEex_GetActorSpellState(targetID, 17) then
				trueAPR = trueAPR + 1
			end
			local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
			if bit.band(stateValue, 0x8000) > 0 then
				trueAPR = trueAPR + 1
			end
			if bit.band(stateValue, 0x10000) > 0 then
				trueAPR = trueAPR - 1
			end
			if trueAPR > 5 then
				trueAPR = 5
			end
			IEex_WriteWord(creatureData + 0x93A, trueAPR)
			IEex_WriteWord(creatureData + 0x1792, trueAPR)
--		end
		local monkACBonusDisabled, fixMonkACBonus = IEex_CheckMonkACBonus(creatureData)
		if not monkACBonusDisabled or fixMonkACBonus then
			movementRate = movementRate + math.floor(monkLevel / 3) * 3
		end
		if monkACBonusDisabled and fixMonkACBonus then
			local wisdomBonus = math.floor((IEex_GetActorStat(targetID, 39) - 10) / 2)
			if wisdomBonus > 0 then
				IEex_WriteWord(creatureData + 0x92C, IEex_ReadSignedWord(creatureData + 0x92C, 0x0) + wisdomBonus)
			end
		elseif not monkACBonusDisabled and not fixMonkACBonus then
			local wisdomBonus = math.floor((IEex_GetActorStat(targetID, 39) - 10) / 2)
			if wisdomBonus > 0 then
				IEex_WriteWord(creatureData + 0x92C, IEex_ReadSignedWord(creatureData + 0x92C, 0x0) - wisdomBonus)
			end
		end
		
	end

	if IEex_ReadDword(creatureData + 0x4C54) > 0 and IEex_GetActorStat(targetID, 38) < 13 then
--		IEex_WriteDword(creatureData + 0x4C54, 0)
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			if theopcode == 454 then
				IEex_WriteDword(eData + 0x114, 1)
			end
		end)
	end
	if IEex_ReadDword(creatureData + 0x4C58) > 0 and IEex_GetActorStat(targetID, 36) < 13 then
--		IEex_WriteDword(creatureData + 0x4C58, 0)
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			if theopcode == 453 then
				IEex_WriteDword(eData + 0x114, 1)
			end
		end)
	end
	if IEex_ReadDword(creatureData + 0x4C64) > 0 and IEex_GetActorStat(targetID, 40) < 13 then
--		IEex_WriteDword(creatureData + 0x4C64, 0)
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			if theopcode == 457 then
				IEex_WriteDword(eData + 0x114, 1)
			end
		end)
	end

	if IEex_ReadByte(animationData + 0x6, 0x0) ~= 9 or IEex_ReadByte(animationData + 0x7, 0x0) ~= 9 then
		local animation = IEex_ReadDword(creatureData + 0x5C4)
		if ex_new_animation_size[animation] then
			movementRate = movementRate + ex_new_animation_size[animation][3] - ex_animation_size[animation][3]
		end
		local addMovementList = {}
		local setMovement = -1
		local multiplyMovementList = {}
		local hasHaste = false
		local hasImprovedHaste = false
		local hasSlow = false
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if theopcode == 126 or theopcode == 176 or theopcode == 266 then
				if theparameter2 == 0 then
					table.insert(addMovementList, theparameter1)
				elseif theparameter2 == 1 and setMovement ~= 0 then
					setMovement = theparameter1
				elseif theparameter2 == 2 then
					table.insert(multiplyMovementList, theparameter1)
				end
			elseif theopcode == 16 or (theopcode == 500 and theresource == "MEOP16") then
				hasHaste = true
			elseif theopcode == 40 or (theopcode == 500 and theresource == "MEOP40") then
				hasSlow = true
			elseif theopcode == 288 and theparameter2 == 138 then
				hasImprovedHaste = true
			end
		end)
		for k, v in ipairs(addMovementList) do
			movementRate = movementRate + v
		end
		if setMovement ~= -1 then
			movementRate = setMovement
		end
		for k, v in ipairs(multiplyMovementList) do
			movementRate = math.floor(movementRate * v / 100)
		end
		if hasHaste and not hasImprovedHaste then
			movementRate = movementRate * 2
		end
		if hasSlow then
			movementRate = math.floor(movementRate / 2)
		end
		if bit.band(IEex_ReadDword(creatureData + 0x75C), 0x1000) > 0 then
			movementRate = math.floor(movementRate * ex_dash_movement_multiplier / 100)
		end
	end
	if movementRate < 0 then
		movementRate = 0
	elseif movementRate > 255 then
		movementRate = 255
	end
	IEex_WriteByte(animationData + 0x7, movementRate)
	local strengthBonus = math.floor((IEex_GetActorStat(targetID, 36) - 10) / 2)
	local dexterityBonus = math.floor((IEex_GetActorStat(targetID, 40) - 10) / 2)
	if dexterityBonus > strengthBonus then
		local finesseBonus = math.floor(dexterityBonus / 2)
		local race = IEex_ReadByte(creatureData + 0x26, 0x0)
		local subrace = IEex_GetActorStat(targetID, 93)
		local hasWeaponFinesse = (bit.band(IEex_ReadDword(creatureData + 0x764), 0x80) > 0)
		if hasWeaponFinesse or (race == 5 and subrace == 0) then
			local weaponSlot = IEex_ReadByte(creatureData + 0x4BA4, 0x0)
			local weaponHeader = IEex_ReadByte(creatureData + 0x4BA6, 0x0)
			local weaponRES = IEex_GetItemSlotRES(targetID, weaponSlot)
			local weaponWrapper = IEex_DemandRes(weaponRES, "ITM")
			if weaponWrapper:isValid() then
				local itemData = weaponWrapper:getData()
				local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
				local numHeaders = IEex_ReadSignedWord(itemData + 0x68, 0x0)
				if weaponHeader >= numHeaders then
					weaponHeader = 0
				end
				local headerType = IEex_ReadByte(itemData + 0x82 + weaponHeader * 0x38, 0x0)
				local headerFlags = IEex_ReadDword(itemData + 0xA8 + weaponHeader * 0x38)
				if bit.band(IEex_ReadDword(itemData + 0x18), 0x2) > 0 then
					strengthBonus = math.floor(strengthBonus * 1.5)
				end
				local finesseDifference = finesseBonus - strengthBonus
				if bit.band(headerFlags, 0x1) > 0 then
					if finesseDifference > 0 and ((hasWeaponFinesse and ex_weapon_finesse_damage_bonus and (itemType == 16 or itemType == 19)) or (race == 5 and subrace == 0 and ex_lightfoot_halfling_thrown_dexterity_bonus_to_damage and headerType == 2 and itemType ~= 5 and itemType ~= 15 and itemType ~= 27 and itemType ~= 31) or ((race == 2 or race == 183) and ex_elf_large_sword_weapon_finesse and ex_weapon_finesse_damage_bonus and (itemType == 20))) then
						IEex_WriteDword(creatureData + 0xA00, IEex_ReadDword(creatureData + 0xA00) + finesseDifference)
					end
					if (race == 2 or race == 183) and ex_elf_large_sword_weapon_finesse and (itemType == 20) and dexterityBonus - strengthBonus > 0 then
						IEex_WriteByte(creatureData + 0x9F8, IEex_ReadSignedByte(creatureData + 0x9F8, 0x0) + dexterityBonus - strengthBonus)
					end
				end
			end
			weaponWrapper:free()
			if hasWeaponFinesse and weaponSlot >= 43 and weaponSlot <= 49 then
				weaponSlot = weaponSlot + 1
				local offhandRES = IEex_GetItemSlotRES(targetID, weaponSlot)
				local offhandWrapper = IEex_DemandRes(offhandRES, "ITM")
				if offhandWrapper:isValid() then
					local itemData = offhandWrapper:getData()
					local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
					local numHeaders = IEex_ReadSignedWord(itemData + 0x68, 0x0)
					if numHeaders > 0 then
						local headerType = IEex_ReadByte(itemData + 0x82, 0x0)
						local headerFlags = IEex_ReadDword(itemData + 0xA8)
						if headerType == 1 and bit.band(headerFlags, 0x1) > 0 then
							local offhandStrengthBonus = math.floor(strengthBonus / 2)
							if offhandStrengthBonus == 0 and strengthBonus == 1 then
								offhandStrengthBonus = 1
							end
							local finesseDifference = finesseBonus - offhandStrengthBonus
							if finesseDifference > 0 and ex_weapon_finesse_damage_bonus and (itemType == 16 or itemType == 19 or ((race == 2 or race == 183) and ex_elf_large_sword_weapon_finesse and (itemType == 20))) then
								IEex_WriteDword(creatureData + 0xA04, IEex_ReadDword(creatureData + 0xA04) + finesseDifference)
							end
							if (race == 2 or race == 183) and ex_elf_large_sword_weapon_finesse and (itemType == 20) then
								IEex_WriteByte(creatureData + 0x9FC, IEex_ReadSignedByte(creatureData + 0x9FC, 0x0) + dexterityBonus - strengthBonus)
							end
						end
					end
				end
				offhandWrapper:free()
			end
		end
	end
	if IEex_ReadSignedWord(creatureData + 0x720, 0x0) < 0 and IEex_GetActorSpellState(targetID, 218) then
		if IEex_ReadByte(creatureData + 0x24, 0x0) <= 30 then
			IEex_WriteDword(creatureData + 0x920, bit.bor(IEex_ReadDword(creatureData + 0x920), 0x10))
			IEex_WriteByte(creatureData + 0x8A0, 0)
		else
--[[
			if IEex_ReadWord(creatureData + 0x9D2, 0x0) < 180 then
				IEex_WriteWord(creatureData + 0x9D2, 180)
			end
--]]
		end
	end
--[[
	local timeSlowed, targetNotSlowed = IEex_CheckGlobalEffectOnActor(targetID, 0x2)
	if ex_time_slow_speed_divisor == 0x7FFFFFFF then
		if timeSlowed and not targetNotSlowed then
			IEex_WriteDword(creatureData + 0x920, bit.bor(IEex_ReadDword(creatureData + 0x920), 0x20))
		end
	end
--]]
	if finalSetAPR ~= 65535 then
		if finalSetAPR < 0 then
			finalSetAPR = 0
		elseif finalSetAPR > 5 then
			finalSetAPR = 5
		end
		IEex_WriteWord(creatureData + 0x93A, finalSetAPR)
	end
	
	local animationID = IEex_ReadWord(animationData + 0x4, 0x0)
	if animationID == 0x6500 or animationID == 0x6510 then
		IEex_WriteLString(animationData + 0xFB6, "", 8)
	end
	local bardLevel = IEex_GetActorStat(targetID, 97)
	local sorcererLevel = IEex_GetActorStat(targetID, 105)
	if (bardLevel > 0 or sorcererLevel > 0) and IEex_IsPartyMember(targetID) then
		local spells = nil
		for i = 0, 8, 1 do
			local offset = creatureData + 0x360C + i * 0x3C
			local casterClass = IEex_ReadByte(offset + 0x36, 0x0)
			if casterClass == 2 or casterClass == 10 then
				if not spells then
					spells = IEex_FetchSpellInfo(targetID, {1, 6})
				end
				local spellRES = IEex_ReadLString(offset + 0x20, 8)
				local casterType = IEex_CasterClassToType[casterClass]
				if ex_listspll[spellRES] then
					local spellLevel = ex_listspll[spellRES][casterType]
					local levelList = spells[casterType]
					if #levelList >= spellLevel then
						local sorcererCastableCount = levelList[spellLevel][2]
						IEex_WriteWord(offset + 0x18, sorcererCastableCount)
						if sorcererCastableCount > 0 then
							IEex_WriteByte(offset + 0x3A, 0)
						else
							IEex_WriteByte(offset + 0x3A, 1)
						end
					end
				end
			end
		end
	end
end
ex_rndbase_attack_begin = {
[0] = {},
[1] = {0},
[2] = {0, 40},
[3] = {0, 29, 60},
[4] = {0, 19, 39, 59},
[5] = {0, 18, 36, 52, 69},
}
ex_rndbase_attack_end = {
[0] = {},
[1] = {99},
[2] = {39, 99},
[3] = {28, 59, 99},
[4] = {18, 38, 58, 99},
[5] = {17, 35, 51, 68, 99},
}
ex_apr_animation_cutoff_point = 25
ex_record_attack_stats = {}
ex_record_attack_stats_hidden_difference = {}
ex_record_attacks_made = {}
ex_yuanti_attacks_made = {}
ex_yuanti_true_attack_counter = {}
function IEex_ExtraAttacks(creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local tempFlags = IEex_ReadWord(creatureData + 0x9FA, 0x0)
	local newEvaluation = false
	local attackBonus = IEex_ReadSignedWord(creatureData + 0x938, 0x0)
	local criticalHitBonus = IEex_ReadSignedWord(creatureData + 0x936, 0x0)
	local attackPenaltyIncrement = 5
	if bit.band(tempFlags, 0x2) > 0 and ex_record_attack_stats[targetID] ~= nil then
		attackBonus = ex_record_attack_stats[targetID][1]
		criticalHitBonus = ex_record_attack_stats[targetID][2]
		IEex_WriteWord(creatureData + 0x936, criticalHitBonus)
		IEex_WriteWord(creatureData + 0x938, attackBonus)
		IEex_WriteWord(creatureData + 0x178E, criticalHitBonus)
		IEex_WriteWord(creatureData + 0x1790, attackBonus)
	end
	local attackCounter = IEex_ReadSignedByte(creatureData + 0x5622, 0x0)
	if false then
		local animationIncrement = 1
		IEex_IncrementAnimationFrame(creatureData, animationIncrement)
	end
	local timeSlowed, targetNotSlowed = IEex_CheckGlobalEffectOnActor(targetID, 0x2)
	if IEex_GetGameTick() % ex_time_slow_speed_divisor ~= 0 then
		if timeSlowed and not targetNotSlowed then
			IEex_WriteWord(creatureData + 0x5322, 0)

			local castCounter = IEex_ReadSignedWord(creatureData + 0x54E8, 0x0)
			if castCounter > 0 then
				IEex_WriteWord(creatureData + 0x54E8, castCounter - 1)
			end
			local visualEffects = IEex_ReadDword(creatureData + 0xA2C)
			if visualEffects > 0 then
				for i = 0, 31, 1 do
					if bit.band(visualEffects, 2 ^ i) ~= 0 then
						local frame = IEex_ReadSignedWord(creatureData + 0x760C + i * 0xDA, 0x0)
						if frame > 0 then
							IEex_WriteWord(creatureData + 0x760C + i * 0xDA, frame - 1)
						end
					end
				end
			end
		end
	end
	local animation = IEex_ReadDword(creatureData + 0x5C4)
	local hasLongAnimation = (animation == 57690 or animation == 61710 or animation == 61726)
	if attackCounter < 0 then
--[[
		if hasLongAnimation then
			if ex_yuanti_attacks_made[targetID] ~= nil then
			end
			ex_yuanti_attacks_made[targetID] = nil
			ex_yuanti_true_attack_counter[targetID] = nil
		end
--]]
		return
	end
	local normalAPR = IEex_GetActorStat(targetID, 8)
	local currentAttack = IEex_ReadByte(creatureData + 0x5636, 0x0)
	ex_record_attack_stats_hidden_difference[targetID] = {0, 0}
	if bit.band(tempFlags, 0x2) == 0 then
		tempFlags = bit.bor(tempFlags, 0x2)
		IEex_WriteWord(creatureData + 0x9FA, tempFlags)
		newEvaluation = true
		ex_record_attack_stats[targetID] = {attackBonus, criticalHitBonus}
	end
	local speedFactor = IEex_ReadByte(creatureData + 0x5604, 0x0)
	local combatReflexesFeatID = ex_feat_name_id["ME_COMBAT_REFLEXES"]
	local combatReflexesFeatCount = 0
	if combatReflexesFeatID ~= nil then
		combatReflexesFeatCount = IEex_ReadByte(creatureData + 0x744 + combatReflexesFeatID, 0x0)
	end
	local opportunistFeatID = ex_feat_name_id["ME_OPPORTUNIST"]
	local opportunistFeatCount = 0
	if opportunistFeatID ~= nil then
		opportunistFeatCount = IEex_ReadByte(creatureData + 0x744 + opportunistFeatID, 0x0)
	end
	local maxAttacksOfOpportunity = ex_base_num_attacks_of_opportunity
	if combatReflexesFeatCount > 0 and ex_base_num_attacks_of_opportunity == 0 then
		maxAttacksOfOpportunity = 1
	end
	if combatReflexesFeatCount > 1 or (combatReflexesFeatCount > 0 and ex_base_num_attacks_of_opportunity > 0) then
		maxAttacksOfOpportunity = maxAttacksOfOpportunity + math.floor((IEex_GetActorStat(targetID, 40) - 10) / 2)
		if maxAttacksOfOpportunity < 1 then
			maxAttacksOfOpportunity = 1
		end
	end
	local imptwfFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_IMPROVED_TWO_WEAPON_FIGHTING"], 0x0)
	local manyshotFeatCount = IEex_ReadByte(creatureData + 0x744 + ex_feat_name_id["ME_MANYSHOT"], 0x0)
	local rapidShotEnabled = (IEex_ReadByte(creatureData + 0x4C64, 0x0) > 0)
	local rapidShotActive = false
	local monkLevel = IEex_GetActorStat(targetID, 101)

	local monkAttackBonusDisabled, fixMonkAttackBonus = IEex_CheckMonkAttackBonus(creatureData)
	local monkAttackBonusNowEnabled = (monkLevel > 0 and (not monkAttackBonusDisabled or fixMonkAttackBonus))
	local isFistWeapon = false
	local isBow = false
	local isRanged = false
	local isLauncher = false
	local wearingLightArmor = true
	local isOffhandAttack = false
	local hasSpecificCritBonuses = false
	local numWeapons = 0
	local headerType = 1
	local range = 1
	local weaponSlot = IEex_ReadByte(creatureData + 0x4BA4, 0x0)
	local weaponHeader = IEex_ReadByte(creatureData + 0x4BA6, 0x0)
	local weaponRES = ""
	local offhandRES = ""
	local slotData = IEex_ReadDword(creatureData + 0x4AD8 + weaponSlot * 0x4)
	local weaponWrapper = 0
	local offhandWrapper = 0
	local offhandWrapperUsed = false
	local launcherWrapper = 0
	if slotData > 0 then
		weaponRES = IEex_ReadLString(slotData + 0xC, 8)
		weaponWrapper = IEex_DemandRes(weaponRES, "ITM")
		if weaponWrapper:isValid() then
			local itemData = weaponWrapper:getData()
			local numHeaders = IEex_ReadSignedWord(itemData + 0x68, 0x0)
			if weaponHeader >= numHeaders then
				weaponHeader = 0
			end
			headerType = IEex_ReadByte(itemData + 0x82 + weaponHeader * 0x38, 0x0)
			range = IEex_ReadWord(itemData + 0x90 + weaponHeader * 0x38, 0x0)
			local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
			if headerType == 2 then
				isRanged = true
				if rapidShotEnabled and itemType ~= 27 and itemType ~= 31 then
					rapidShotActive = true
				end
			end
		end
	end
	local bitmapWrapper = IEex_DemandRes("RNDBASE" .. normalAPR, "BMP")
	local aboutToAttack = false
	local aboutToSwing = false
	local justAttacked = false
	if bitmapWrapper:isValid() then
		local bitmapData = bitmapWrapper:getData()
		local nextPixelColor = IEex_GetBitmapPixelColor(bitmapData, attackCounter + 1, speedFactor)
		aboutToAttack = (nextPixelColor == 0xFF0000)
		aboutToSwing = (nextPixelColor == 0xFF00 or nextPixelColor == 0xFFFF00 or nextPixelColor == 0xFF or nextPixelColor == 0xFF00FF or nextPixelColor == 0xFFFF)
		justAttacked = (IEex_GetBitmapPixelColor(bitmapData, attackCounter, speedFactor) == 0xFF0000)
		if justAttacked and IEex_GetActorSpellState(targetID, 246) then
			local sourceAnimationSequence = IEex_ReadByte(creatureData + 0x50F4, 0x0)
			if sourceAnimationSequence == 0 or sourceAnimationSequence == 8 or sourceAnimationSequence == 11 or sourceAnimationSequence == 12 or sourceAnimationSequence == 13 then
				IEex_IterateActorEffects(targetID, function(eData)
					local theopcode = IEex_ReadDword(eData + 0x10)
					local theparameter2 = IEex_ReadDword(eData + 0x20)
					local thesavingthrow = IEex_ReadDword(eData + 0x40)
					if theopcode == 288 and theparameter2 == 246 and bit.band(thesavingthrow, 0x100000) > 0 then
						local thelimit = IEex_ReadSignedWord(eData + 0x4A, 0x0)
						if thelimit > 0 then
							thelimit = thelimit - 1
							IEex_WriteWord(eData + 0x4A, thelimit)
						end
					end
				end)
			end
		end
	end
	if IEex_GetGameTick() % ex_time_slow_speed_divisor ~= 0 and timeSlowed and not targetNotSlowed and not justAttacked and attackCounter > 0 then
		attackCounter = attackCounter - 1
		IEex_WriteByte(creatureData + 0x5622, attackCounter)
	end
	if false then
		if not aboutToAttack and not aboutToSwing and attackCounter > 0 and attackCounter < 100 then
			attackCounter = attackCounter + 1
			IEex_WriteByte(creatureData + 0x5622, attackCounter)
		end
	end
	if false and IEex_GetGameTick() % 2 == 0 then
		if not justAttacked and attackCounter > 0 then
			attackCounter = attackCounter - 1
			IEex_WriteByte(creatureData + 0x5622, attackCounter)
		end
	end
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter1 = IEex_ReadDword(eData + 0x1C)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local thespecial = IEex_ReadDword(eData + 0x48)
		if theopcode == 288 and theparameter2 == 241 then
			local thegeneralitemcategory = IEex_ReadByte(eData + 0x48, 0x0)
			if thegeneralitemcategory == 5 then
				numWeapons = numWeapons + 1
			elseif thegeneralitemcategory == 6 then
				isFistWeapon = true
			elseif (theparameter1 >= 62 and theparameter1 <= 66) or theparameter1 == 68 then
				wearingLightArmor = false
			elseif theparameter1 == 15 then
				isBow = true
			end
			if thegeneralitemcategory == 7 then
				isLauncher = true
				launcherWrapper = IEex_DemandRes(IEex_ReadLString(eData + 0x94, 8), "ITM")
			end
		elseif theopcode == 500 and theresource == "MECRIT" and bit.band(thesavingthrow, 0x100000) > 0 then
			hasSpecificCritBonuses = true
		end
	end)
	if hasLongAnimation and not isBow then
		hasLongAnimation = false
		ex_yuanti_attacks_made[targetID] = nil
		ex_yuanti_true_attack_counter[targetID] = nil
	end
	if weaponSlot == 42 and numWeapons >= 2 then
		numWeapons = 1
	end
	if numWeapons >= 2 and currentAttack == normalAPR then
		isOffhandAttack = true
	end
	if numWeapons >= 2 and weaponSlot >= 43 then
		local offhandSlotData = IEex_ReadDword(creatureData + 0x4AD8 + (weaponSlot + 1) * 0x4)
		if offhandSlotData > 0 then
			offhandRES = IEex_ReadLString(offhandSlotData + 0xC, 8)
			offhandWrapper = IEex_DemandRes(offhandRES, "ITM")
			offhandWrapperUsed = true
		end
	end
	if monkAttackBonusDisabled and fixMonkAttackBonus and monkLevel > 0 and currentAttack > 0 then
		local firstFiveAttacksDisabled = {0, 0, 0, 0, 0}
		local firstFiveAttacksFixed = {0, 0, 0, 0, 0}
		firstFiveAttacksDisabled[1] = tonumber(IEex_2DAGetAtStrings("BAATNFG", "BASE_ATTACK", tostring(monkLevel)))
		firstFiveAttacksFixed[1] = tonumber(IEex_2DAGetAtStrings("BAATMKU", "BASE_ATTACK", tostring(monkLevel)))
		for i = 2, 5, 1 do
			if i == 2 and rapidShotActive then
				firstFiveAttacksDisabled[i] = firstFiveAttacksDisabled[i - 1]
				firstFiveAttacksFixed[i] = firstFiveAttacksFixed[i - 1]
			else
				firstFiveAttacksDisabled[i] = firstFiveAttacksDisabled[i - 1] - 5
				if firstFiveAttacksDisabled[i] < 0 then
					firstFiveAttacksDisabled[i] = 0
				end
				firstFiveAttacksFixed[i] = firstFiveAttacksFixed[i - 1] - 3
			end
		end
		attackBonus = attackBonus + firstFiveAttacksFixed[currentAttack] - firstFiveAttacksDisabled[currentAttack]
--[[
		attackBonus = attackBonus + tonumber(IEex_2DAGetAtStrings("BAATMKU", "BASE_ATTACK", tostring(monkLevel))) - tonumber(IEex_2DAGetAtStrings("BAATNFG", "BASE_ATTACK", tostring(monkLevel)))
		if currentAttack >= 2 then
			attackBonus = attackBonus + 2 * (currentAttack - 1)
		end
		if currentAttack >= 5 then
			attackBonus = attackBonus - 5
		end
--]]
	end
	local extraMonkAttacks = 0
	if monkAttackBonusNowEnabled then
		attackPenaltyIncrement = 3
		extraMonkAttacks = ex_monk_apr_progression[monkLevel]
		if weaponRES == ex_monk_fist_progression[monkLevel] or weaponRES == ex_incorporeal_monk_fist_progression[monkLevel] or string.sub(weaponRES, 1, 7) == "00MFIST" then
			extraMonkAttacks = extraMonkAttacks + 1
		end
	end
	local doAttackOfOpportunity = false
	local opportunityAttackBonus = 0
	local actionID = IEex_ReadWord(creatureData + 0x476, 0x0)
	local actionTargetID = IEex_ReadDword(creatureData + 0x4BE)
	if not IEex_IsSprite(actionTargetID, true) then
		actionTargetID = IEex_ReadDword(creatureData + 0x5690)
	end
	local actionTargetData = IEex_GetActorShare(actionTargetID)
	local targetX, targetY = IEex_GetActorLocation(targetID)
	local actionTargetX, actionTargetY = IEex_GetActorLocation(actionTargetID)
	if maxAttacksOfOpportunity > 0 and IEex_CompareActorAllegiances(targetID, actionTargetID) == -1 and not (timeSlowed and not targetNotSlowed and ex_time_slow_speed_divisor == 0x7FFFFFFF) and not IEex_GetActorState(targetID, 0x80100FED) and (IEex_GetActorStat(targetID, 81) > 0 or (actionTargetData > 0 and IEex_ReadByte(actionTargetData + 0x8A0, 0x0) == 0)) then
		if actionID == 3 or actionID == 94 or actionID == 105 or actionID == 134 then
			local ignoreFleeingOpportunity = ex_no_attacks_of_opportunity_on_fleeing
			local ignoreRangedWeaponOpportunity = ex_no_attacks_of_opportunity_on_ranged_attack
			local ignoreSpellCastOpportunity = ex_no_attacks_of_opportunity_on_spell_cast
			local ignoreOpportunistOpportunity = (opportunistFeatCount == 0)
			local fleeingOpportunityAttackBonus = 0
			local rangedWeaponOpportunityAttackBonus = 0
			local spellCastOpportunityAttackBonus = 0
			local opportunistOpportunityAttackBonus = 0
			IEex_IterateActorEffects(actionTargetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				if theopcode == 288 and theparameter2 == 231 then
					if bit.band(thesavingthrow, 0x10000) > 0 then
						if theparameter1 ~= 0 then
							fleeingOpportunityAttackBonus = fleeingOpportunityAttackBonus - theparameter1
						else
							ignoreFleeingOpportunity = true
						end
					end
					if bit.band(thesavingthrow, 0x20000) > 0 then
						if theparameter1 ~= 0 then
							rangedWeaponOpportunityAttackBonus = rangedWeaponOpportunityAttackBonus - theparameter1
						else
							ignoreRangedWeaponOpportunity = true
						end
					end
					if bit.band(thesavingthrow, 0x40000) > 0 then
						if theparameter1 ~= 0 then
							spellCastOpportunityAttackBonus = spellCastOpportunityAttackBonus - theparameter1
						else
							ignoreSpellCastOpportunity = true
						end
					end
					if bit.band(thesavingthrow, 0x80000) > 0 then
						if theparameter1 ~= 0 then
							opportunistOpportunityAttackBonus = opportunistOpportunityAttackBonus - theparameter1
						else
							ignoreOpportunistOpportunity = true
						end
					end
					if bit.band(thesavingthrow, 0xF0000) == 0 then
						if theparameter1 ~= 0 then
							fleeingOpportunityAttackBonus = fleeingOpportunityAttackBonus - theparameter1
							rangedWeaponOpportunityAttackBonus = rangedWeaponOpportunityAttackBonus - theparameter1
							spellCastOpportunityAttackBonus = spellCastOpportunityAttackBonus - theparameter1
							opportunistOpportunityAttackBonus = opportunistOpportunityAttackBonus - theparameter1
						else
							ignoreFleeingOpportunity = true
							ignoreRangedWeaponOpportunity = true
							ignoreSpellCastOpportunity = true
							ignoreOpportunistOpportunity = true
						end
					end
				elseif theopcode == 500 and theresource == "MEAPRBON" then
					if IEex_GetGameTick() < IEex_ReadDword(eData + 0x60) then
						ignoreFleeingOpportunity = true
					end
				end
			end)
			local tick = IEex_GetGameTick()
			if headerType ~= 1 or not IEex_IsSprite(actionTargetID, false) then
				ex_attopp_target[targetID] = nil
				ex_attopp_range[targetID] = nil
			else
				if ex_attopp_repeat_timer[targetID] == nil then
					ex_attopp_repeat_timer[targetID] = {}
				end
				if IEex_GetDistance(targetX, targetY, actionTargetX, actionTargetY) <= range * 20 + 40 then
					ex_attopp_target[targetID] = actionTargetID
					ex_attopp_range[targetID] = range
					local animationSequence = IEex_ReadByte(IEex_GetActorShare(actionTargetID) + 0x50F4, 0x0)
					local actionTargetHasRangedWeapon = false
					if animationSequence == 0 or animationSequence == 8 or animationSequence == 11 or animationSequence == 12 or animationSequence == 13 then
						weaponSlot = IEex_ReadByte(actionTargetData + 0x4BA4, 0x0)
						weaponHeader = IEex_ReadByte(actionTargetData + 0x4BA6, 0x0)
						slotData = IEex_ReadDword(actionTargetData + 0x4AD8 + weaponSlot * 0x4)
						if slotData > 0 then
							local weaponRES = IEex_ReadLString(slotData + 0xC, 8)
							local resWrapper = IEex_DemandRes(weaponRES, "ITM")
							if resWrapper:isValid() then
								local itemData = resWrapper:getData()
								local numHeaders = IEex_ReadSignedWord(itemData + 0x68, 0x0)
								if weaponHeader >= numHeaders then
									weaponHeader = 0
								end
								if IEex_ReadByte(itemData + 0x82 + weaponHeader * 0x38, 0x0) ~= 1 then
									actionTargetHasRangedWeapon = true
								end
							end
							resWrapper:free()
						end
					end
					if (animationSequence == 2 or animationSequence == 3) and ex_attopp_casting[actionTargetID] and not ex_attopp_casting[actionTargetID][targetID] and not ignoreSpellCastOpportunity and (ex_attopp_repeat_timer[targetID][actionTargetID] == nil or tick - ex_attopp_repeat_timer[targetID][actionTargetID] >= 30) then
						if ex_attopp_count[targetID] == nil or (ex_attopp_timer[targetID] ~= nil and tick - ex_attopp_timer[targetID] >= 100) then
							ex_attopp_count[targetID] = 0
							ex_attopp_timer[targetID] = tick
						end
						if ex_attopp_count[targetID] < maxAttacksOfOpportunity then
							ex_attopp_count[targetID] = ex_attopp_count[targetID] + 1
							ex_attopp_repeat_timer[targetID][actionTargetID] = tick
							ex_attopp_casting[actionTargetID][targetID] = true
							opportunityAttackBonus = spellCastOpportunityAttackBonus
							doAttackOfOpportunity = true
						end
					elseif actionTargetHasRangedWeapon and not ignoreRangedWeaponOpportunity and (ex_attopp_repeat_timer[targetID][actionTargetID] == nil or tick - ex_attopp_repeat_timer[targetID][actionTargetID] >= 30) then
						if ex_attopp_count[targetID] == nil or (ex_attopp_timer[targetID] ~= nil and tick - ex_attopp_timer[targetID] >= 100) then
							ex_attopp_count[targetID] = 0
							ex_attopp_timer[targetID] = tick
						end
						if ex_attopp_count[targetID] < maxAttacksOfOpportunity then
							ex_attopp_count[targetID] = ex_attopp_count[targetID] + 1
							ex_attopp_repeat_timer[targetID][actionTargetID] = tick
							opportunityAttackBonus = rangedWeaponOpportunityAttackBonus
							doAttackOfOpportunity = true
						end
					elseif not ignoreOpportunistOpportunity and ex_attopp_opportunist[actionTargetID] ~= nil and (ex_attopp_repeat_timer[targetID][actionTargetID] == nil or tick - ex_attopp_repeat_timer[targetID][actionTargetID] >= 30) then
						local doOpportunist = false
						for k, v in pairs(ex_attopp_opportunist[actionTargetID]) do
							if k ~= targetID and tick - v <= 4 and IEex_CompareActorAllegiances(targetID, k) == 1 then
								doOpportunist = true
							end
						end
						if doOpportunist then
							if ex_attopp_count[targetID] == nil or (ex_attopp_timer[targetID] ~= nil and tick - ex_attopp_timer[targetID] >= 100) then
								ex_attopp_count[targetID] = 0
								ex_attopp_timer[targetID] = tick
							end
							if ex_attopp_count[targetID] < maxAttacksOfOpportunity then
								ex_attopp_count[targetID] = ex_attopp_count[targetID] + 1
								ex_attopp_repeat_timer[targetID][actionTargetID] = tick
								opportunityAttackBonus = opportunistOpportunityAttackBonus
								doAttackOfOpportunity = true
							end
						end
					end
				else
					if ex_attopp_target[targetID] == actionTargetID and not ignoreFleeingOpportunity and (ex_attopp_repeat_timer[targetID][actionTargetID] == nil or tick - ex_attopp_repeat_timer[targetID][actionTargetID] >= 30) and ex_attopp_range[targetID] == range then
						if ex_attopp_count[targetID] == nil or (ex_attopp_timer[targetID] ~= nil and tick - ex_attopp_timer[targetID] >= 100) then
							ex_attopp_count[targetID] = 0
							ex_attopp_timer[targetID] = tick
						end
						if ex_attopp_count[targetID] < maxAttacksOfOpportunity then
							ex_attopp_count[targetID] = ex_attopp_count[targetID] + 1
							ex_attopp_repeat_timer[targetID][actionTargetID] = tick
							opportunityAttackBonus = fleeingOpportunityAttackBonus
							doAttackOfOpportunity = true
						end
					end
					ex_attopp_target[targetID] = nil
					ex_attopp_range[targetID] = nil
				end
			end
		else
			ex_attopp_target[targetID] = nil
			ex_attopp_range[targetID] = nil
		end
	end
	if ex_record_attacks_made[targetID] == nil then
		ex_record_attacks_made[targetID] = {0, 0, 0, 0}
	end
	if (normalAPR + imptwfFeatCount + extraMonkAttacks >= 5 or (manyshotFeatCount > 0 and rapidShotEnabled) or hasLongAnimation) and attackCounter >= 0 then
		IEex_WriteWord(creatureData + 0x9E6, 10)
--[[
		if targetID == IEex_GetActorIDCharacter(0) and aboutToAttack then
			IEex_Search_Change(1, creatureData + 0x5600, 0x90, false)
		end
--]]
		IEex_WriteByte(creatureData + 0x5604, 0)
		local totalAttacks = IEex_ReadByte(creatureData + 0x5ED, 0x0) + extraMonkAttacks
		local extraMainhandAttacks = extraMonkAttacks
		local extraAttacks = 0
		local manyshotAttacks = manyshotFeatCount
		local setAPR = -1
		if weaponWrapper:isValid() then
			local weaponData = weaponWrapper:getData()
			local numHeaders = IEex_ReadSignedWord(weaponData + 0x68, 0x0)
			if weaponHeader >= numHeaders then
				weaponHeader = 0
			end
			local itemType = IEex_ReadWord(weaponData + 0x1C, 0x0)
			headerType = IEex_ReadByte(weaponData + 0x82 + weaponHeader * 0x38, 0x0)
			if rapidShotEnabled and headerType == 2 and itemType ~= 27 and itemType ~= 31 then
				totalAttacks = totalAttacks + 1
				extraMainhandAttacks = extraMainhandAttacks + 1
			end
			local effectOffset = IEex_ReadDword(weaponData + 0x6A)
			local numGlobalEffects = IEex_ReadWord(weaponData + 0x70, 0x0)
			for i = 0, numGlobalEffects - 1, 1 do
				local offset = weaponData + effectOffset + i * 0x30
				local theopcode = IEex_ReadWord(offset, 0x0)
				local theparameter2 = IEex_ReadDword(offset + 0x8)
				if theopcode == 1 and theparameter2 == 0 then
					local theparameter1 = IEex_ReadDword(offset + 0x4)
					totalAttacks = totalAttacks + theparameter1
					extraMainhandAttacks = extraMainhandAttacks + theparameter1
				end
			end
		end
		if offhandWrapperUsed and offhandWrapper:isValid() then
			local weaponData = offhandWrapper:getData()
			local effectOffset = IEex_ReadDword(weaponData + 0x6A)
			local numGlobalEffects = IEex_ReadWord(weaponData + 0x70, 0x0)
			for i = 0, numGlobalEffects - 1, 1 do
				local offset = weaponData + effectOffset + i * 0x30
				local theopcode = IEex_ReadWord(offset, 0x0)
				local theparameter2 = IEex_ReadDword(offset + 0x8)
				if theopcode == 1 and theparameter2 == 0 then
					local theparameter1 = IEex_ReadDword(offset + 0x4)
					totalAttacks = totalAttacks + theparameter1
					extraAttacks = extraAttacks + theparameter1
				end
			end
		end

		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			local thespecial = IEex_ReadDword(eData + 0x48)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theopcode == 1 then
				if theparameter2 == 0 and theparent_resource ~= weaponRES and theparent_resource ~= offhandRES then
					totalAttacks = totalAttacks + theparameter1
					if bit.band(thesavingthrow, 0x100000) > 0 and offhandRES ~= "" then
						extraAttacks = extraAttacks + theparameter1
					else
						extraMainhandAttacks = extraMainhandAttacks + theparameter1
					end
				elseif theparameter2 == 1 then
					totalAttacks = theparameter1
					if setAPR ~= 0 then
						setAPR = theparameter1
					end
				end
			elseif theopcode == 288 and theparameter2 == 196 and (thespecial == 0 or thespecial == headerType) then
				if bit.band(thesavingthrow, 0x20000) > 0 then
					manyshotAttacks = manyshotAttacks + theparameter1
				end
--[[
			elseif theopcode == 288 and theparameter2 == 241 then
				local thegeneralitemcategory = IEex_ReadByte(eData + 0x48, 0x0)
				if thegeneralitemcategory == 5 then
					numWeapons = numWeapons + 1
				elseif thegeneralitemcategory == 6 then
					isFistWeapon = true
				elseif (theparameter1 >= 62 and theparameter1 <= 66) or theparameter1 == 68 then
					wearingLightArmor = false
				elseif theparameter1 == 15 then
					isBow = true
				end

			elseif theopcode == 500 and IEex_ReadLString(eData + 0x30, 8) == "MECRIT" and IEex_ReadSignedWord(eData + 0x4A, 0x0) > 0 and then
				local thegeneralitemcategory = IEex_ReadByte(eData + 0x48, 0x0)
				if thegeneralitemcategory == 5 then
					numWeapons = numWeapons + 1
				elseif thegeneralitemcategory == 6 then
					isFistWeapon = true
				elseif (theparameter1 >= 62 and theparameter1 <= 66) or theparameter1 == 68 then
					wearingLightArmor = false
				elseif theparameter1 == 15 then
					isBow = true
				end
--]]
			end

		end)

		if not isBow or not rapidShotEnabled then
			manyshotAttacks = 0
		end
		local usingImptwf = false
		if numWeapons >= 2 then
			totalAttacks = totalAttacks + 1
		end
		local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
		if bit.band(stateValue, 0x8000) > 0 then
			totalAttacks = totalAttacks + 1
			extraMainhandAttacks = extraMainhandAttacks + 1
		end
		if bit.band(stateValue, 0x10000) > 0 then
			totalAttacks = totalAttacks - 1
			extraMainhandAttacks = extraMainhandAttacks - 1
		end
		if numWeapons >= 2 then
			if imptwfFeatCount > 0 and (IEex_GetActorStat(targetID, 103) < 9 or wearingLightArmor or (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 16 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x2) > 0 and bit.band(IEex_ReadDword(creatureData + 0x764), 0x40) > 0)) then
				totalAttacks = totalAttacks + 1
				extraAttacks = extraAttacks + 1
				usingImptwf = true
				if imptwfFeatCount > 1 and (IEex_GetActorStat(targetID, 103) < 14 or wearingLightArmor or (IEex_ReadByte(creatureData + 0x5EC, 0x0) >= 21 and bit.band(IEex_ReadDword(creatureData + 0x75C), 0x2) > 0 and bit.band(IEex_ReadDword(creatureData + 0x764), 0x40) > 0)) then
					totalAttacks = totalAttacks + 1
					extraAttacks = extraAttacks + 1
				end
			end
		else
			extraAttacks = extraAttacks + extraMainhandAttacks
			extraMainhandAttacks = 0
			if normalAPR == 5 then
				extraAttacks = extraAttacks + IEex_ReadByte(creatureData + 0x5ED, 0x0) - normalAPR
				if extraAttacks < 0 then
					extraAttacks = 0
				end
			end
		end
		if IEex_GetActorSpellState(targetID, 138) then
			if numWeapons >= 2 then
				extraMainhandAttacks = extraMainhandAttacks * 2 + (normalAPR - 1)
				extraAttacks = extraAttacks * 2 + 1
			else
				extraAttacks = extraAttacks * 2 + normalAPR
			end
			totalAttacks = normalAPR + extraAttacks + extraMainhandAttacks
			manyshotAttacks = manyshotAttacks * 2
		end
		if imptwfFeatCount > 2 and numWeapons >= 2 then
			extraAttacks = extraMainhandAttacks + (normalAPR - 1)
			totalAttacks = normalAPR + extraAttacks + extraMainhandAttacks + manyshotAttacks
		end
		if hasLongAnimation and normalAPR > 2 and isBow then
			if actionID ~= 3 and actionID ~= 94 and actionID ~= 105 and actionID ~= 134 then
--				ex_yuanti_attacks_made[targetID] = nil
--				ex_yuanti_true_attack_counter[targetID] = nil
				attackCounter = 99
				IEex_WriteByte(creatureData + 0x5622, attackCounter)
			else
				local manyshotAttacksMade = ex_record_attacks_made[targetID][4]
				local animationData = IEex_ReadDword(creatureData + 0x50F0)
				IEex_WriteByte(creatureData + 0x5604, 0)
--				IEex_WriteByte(creatureData + 0x5630, 1)
				if attackCounter == 0 then
					if ex_yuanti_attacks_made[targetID] == nil or ex_yuanti_attacks_made[targetID] == normalAPR then
						ex_yuanti_attacks_made[targetID] = 1
						ex_yuanti_true_attack_counter[targetID] = 0
						ex_record_attacks_made[targetID] = {0, 0, 0, 0}
					else
						ex_yuanti_attacks_made[targetID] = ex_yuanti_attacks_made[targetID] + 1
					end
					currentAttack = ex_yuanti_attacks_made[targetID]
					IEex_WriteByte(creatureData + 0x5636, currentAttack)

				end
				local rndbaseAttackStart = ex_rndbase_attack_begin[normalAPR][currentAttack]
				local rndbaseAttackEnd = ex_rndbase_attack_end[normalAPR][currentAttack]
				local skip = 22 - ex_rndbase_attack_end[normalAPR][1]
				if currentAttack == 1 and attackCounter == 23 and manyshotAttacksMade < manyshotAttacks then
					manyshotAttacksMade = manyshotAttacksMade + 1
					ex_record_attacks_made[targetID][4] = manyshotAttacksMade
					ex_yuanti_true_attack_counter[targetID] = ex_yuanti_true_attack_counter[targetID] - 1
					attackCounter = 0
					IEex_WriteByte(creatureData + 0x5622, attackCounter)
				elseif currentAttack == 1 and attackCounter == 1 and manyshotAttacksMade > 0 then
					ex_yuanti_true_attack_counter[targetID] = ex_yuanti_true_attack_counter[targetID] - 1
					attackCounter = 22
					IEex_WriteByte(creatureData + 0x5622, attackCounter)
				elseif normalAPR <= 3 then
					if attackCounter == ex_rndbase_attack_end[normalAPR][1] then
						if ex_yuanti_true_attack_counter[targetID] < rndbaseAttackEnd then
							attackCounter = attackCounter - 1
							IEex_WriteByte(creatureData + 0x5622, attackCounter)
						else
							attackCounter = 99
							IEex_WriteByte(creatureData + 0x5622, attackCounter)
							IEex_WriteWord(animationData + 0x9EE, 30)
							IEex_WriteWord(animationData + 0xAC8, 30)
						end
					end
				else
					if attackCounter == 0 then
						IEex_WriteWord(animationData + 0x9EE, IEex_ReadSignedWord(animationData + 0x9EE, 0x0) + skip)
						IEex_WriteWord(animationData + 0xAC8, IEex_ReadSignedWord(animationData + 0xAC8, 0x0) + skip)
					elseif attackCounter == 23 then
						if ex_yuanti_true_attack_counter[targetID] >= rndbaseAttackEnd then
							attackCounter = 99
							IEex_WriteByte(creatureData + 0x5622, attackCounter)
							if currentAttack == 1 then
								ex_yuanti_true_attack_counter[targetID] = ex_yuanti_true_attack_counter[targetID] - 1
							end
							IEex_WriteWord(animationData + 0x9EE, 30)
							IEex_WriteWord(animationData + 0xAC8, 30)
						end
					elseif attackCounter == 24 then
						if ex_yuanti_true_attack_counter[targetID] < rndbaseAttackEnd then
							attackCounter = attackCounter - 1
							IEex_WriteByte(creatureData + 0x5622, attackCounter)
						else
							attackCounter = 99
							IEex_WriteByte(creatureData + 0x5622, attackCounter)
							if currentAttack == 1 then
								ex_yuanti_true_attack_counter[targetID] = ex_yuanti_true_attack_counter[targetID] - 1
							end
							IEex_WriteWord(animationData + 0x9EE, 30)
							IEex_WriteWord(animationData + 0xAC8, 30)
						end
					elseif attackCounter == ex_rndbase_attack_end[normalAPR][1] then
						attackCounter = 22
						IEex_WriteByte(creatureData + 0x5622, attackCounter)
					end
				end
				if currentAttack == 1 and attackCounter == 22 then
					attackBonus = attackBonus - attackPenaltyIncrement * manyshotAttacks
				end
				ex_yuanti_true_attack_counter[targetID] = ex_yuanti_true_attack_counter[targetID] + 1
			end
		elseif totalAttacks >= 6 or usingImptwf or manyshotAttacks > 0 or extraMonkAttacks > 0 then
			local totalAttacksMade = ex_record_attacks_made[targetID][1]
			local extraAttacksMade = ex_record_attacks_made[targetID][2]
			local extraMainhandAttacksMade = ex_record_attacks_made[targetID][3]
			local manyshotAttacksMade = ex_record_attacks_made[targetID][4]
			IEex_WriteByte(creatureData + 0x5630, 1)
			if normalAPR == 4 then
				local counterCut = 0
				local remainderCut = 0
				if usingImptwf or extraMonkAttacks > 0 then
					counterCut = 3
					remainderCut = 5
					extraAttacks = 1
				else
					extraAttacks = 0
				end
				extraMainhandAttacks = 0
				if attackCounter == 6 and manyshotAttacksMade < manyshotAttacks then
					manyshotAttacksMade = manyshotAttacksMade + 1
					ex_record_attacks_made[targetID][4] = manyshotAttacksMade
					IEex_WriteByte(creatureData + 0x5622, 0)
				elseif attackCounter == 1 and manyshotAttacksMade > 0 then
					attackCounter = 5
					IEex_WriteByte(creatureData + 0x5622, attackCounter)
					aboutToAttack = true
				elseif attackCounter >= 19 - counterCut and attackCounter >= 6 and attackCounter < 19 then
					if totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 14)
					end
					IEex_WriteByte(creatureData + 0x5622, 18)
				elseif attackCounter >= 39 - counterCut and attackCounter >= 25 and attackCounter < 39 then
					if totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 14)
					end
					IEex_WriteByte(creatureData + 0x5622, 38)
				elseif attackCounter >= 59 - counterCut and attackCounter >= 45 and attackCounter < 59 then
					if totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 14)
					end
					IEex_WriteByte(creatureData + 0x5622, 58)
				elseif attackCounter >= 79 - counterCut and attackCounter >= 65 and attackCounter < 79 and extraAttacksMade < extraAttacks then
					extraAttacksMade = extraAttacksMade + 1
					ex_record_attacks_made[targetID][2] = extraAttacksMade
					if totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 14)
					end
					IEex_WriteByte(creatureData + 0x5622, 58)
				elseif attackCounter >= 80 - counterCut and attackCounter >= 65 and attackCounter < 80 then
					if totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 14)
					end
					IEex_WriteByte(creatureData + 0x5622, 79)
				elseif attackCounter >= 100 - remainderCut and attackCounter >= 80 then
					if totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 14)
					end
					IEex_WriteByte(creatureData + 0x5622, 99)
					ex_record_attacks_made[targetID] = {0, 0, 0, 0}
				elseif attackCounter == 0 then
					ex_record_attacks_made[targetID] = {0, 0, 0, 0}
				end
				if attackCounter == 5 or attackCounter == 24 or attackCounter == 44 or attackCounter == 64 then
					ex_record_attacks_made[targetID][1] = totalAttacksMade + 1
					if IEex_ReadByte(creatureData + 0x5636, 0x0) == 0 then
						if attackCounter == 5 then
							IEex_WriteByte(creatureData + 0x5636, 1)
						elseif attackCounter == 24 then
							IEex_WriteByte(creatureData + 0x5636, 2)
						elseif attackCounter == 44 then
							IEex_WriteByte(creatureData + 0x5636, 3)
						elseif attackCounter == 64 then
							IEex_WriteByte(creatureData + 0x5636, 4)
						end
					end
				end
				if attackCounter == 5 then
					if manyshotAttacks > 0 then
						attackBonus = attackBonus - attackPenaltyIncrement * manyshotAttacks
					end
				elseif attackCounter == 64 then
					attackBonus = attackBonus - attackPenaltyIncrement * extraAttacksMade
				end
			elseif normalAPR == 5 then
				local counterCut = math.floor((extraAttacks + extraMainhandAttacks) * 16 / (totalAttacks + 1))
				local remainderCut = (((extraAttacks + extraMainhandAttacks) * 16) % (totalAttacks + 1)) + counterCut
				if totalAttacks >= 15 then
					counterCut = 100
					remainderCut = 100
				elseif counterCut == 10 then
					remainderCut = remainderCut + 1
				end
				if attackCounter == 6 and manyshotAttacksMade < manyshotAttacks then
					manyshotAttacksMade = manyshotAttacksMade + 1
					ex_record_attacks_made[targetID][4] = manyshotAttacksMade
					IEex_WriteByte(creatureData + 0x5622, 0)
				elseif attackCounter == 1 and manyshotAttacksMade > 0 then
					attackCounter = 5
					IEex_WriteByte(creatureData + 0x5622, attackCounter)
					aboutToAttack = true
				elseif attackCounter >= 18 - counterCut and attackCounter >= 6 and attackCounter < 18 then
					if totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 14)
					end
					IEex_WriteByte(creatureData + 0x5622, 17)
				elseif attackCounter >= 36 - counterCut and attackCounter >= 24 and attackCounter < 36 then
					if totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 14)
					end
					IEex_WriteByte(creatureData + 0x5622, 35)
				elseif attackCounter >= 52 - counterCut and attackCounter >= 42 and attackCounter < 52 then
					if totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 14)
					end
					IEex_WriteByte(creatureData + 0x5622, 51)
				elseif attackCounter >= 68 - counterCut and attackCounter >= 58 and attackCounter < 68 and extraMainhandAttacksMade < extraMainhandAttacks then
					extraMainhandAttacksMade = extraMainhandAttacksMade + 1
					ex_record_attacks_made[targetID][3] = extraMainhandAttacksMade
					if totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 14)
					end
					IEex_WriteByte(creatureData + 0x5622, 51)
				elseif attackCounter >= 69 - counterCut and attackCounter >= 58 and attackCounter < 69 then
					if totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 14)
					end
					IEex_WriteByte(creatureData + 0x5622, 68)
				elseif attackCounter >= 85 - counterCut and attackCounter >= 75 and attackCounter < 85 and extraAttacksMade < extraAttacks then
					extraAttacksMade = extraAttacksMade + 1
					ex_record_attacks_made[targetID][2] = extraAttacksMade
					if totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 14)
					end
					IEex_WriteByte(creatureData + 0x5622, 68)
				elseif attackCounter >= 86 - counterCut and attackCounter >= 75 and attackCounter < 86 then
					if totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 14)
					end
					IEex_WriteByte(creatureData + 0x5622, 85)
				elseif attackCounter >= 100 - remainderCut and attackCounter >= 86 then
					IEex_WriteByte(creatureData + 0x5622, 99)
					ex_record_attacks_made[targetID] = {0, 0, 0, 0}
				elseif attackCounter == 0 then
					ex_record_attacks_made[targetID] = {0, 0, 0, 0}
				end
				if totalAttacks > 50 then
					totalAttacks = 50
				end
				if totalAttacks >= 16 and (attackCounter == 0 or attackCounter == 18 or attackCounter == 36 or attackCounter == 52 or attackCounter == 69) and ex_superfast_attack_cut[totalAttacks][totalAttacksMade + 1] ~= nil then
					attackCounter = attackCounter + ex_superfast_attack_cut[totalAttacks][totalAttacksMade + 1]
					if IEex_IsSprite(actionTargetID, false) and totalAttacks < ex_apr_animation_cutoff_point then
						IEex_SetAttackAnimationFrame(creatureData, 1 + ex_superfast_attack_cut[totalAttacks][totalAttacksMade + 1])
					end
					IEex_WriteByte(creatureData + 0x5622, attackCounter)
				end
				if attackCounter == 5 or attackCounter == 23 or attackCounter == 41 or attackCounter == 57 or attackCounter == 74 then
					ex_record_attacks_made[targetID][1] = totalAttacksMade + 1
--					if IEex_ReadByte(creatureData + 0x5636, 0x0) == 0 then
						if attackCounter == 5 then
							IEex_WriteByte(creatureData + 0x5636, 1)
						elseif attackCounter == 23 then
							IEex_WriteByte(creatureData + 0x5636, 2)
						elseif attackCounter == 41 then
							IEex_WriteByte(creatureData + 0x5636, 3)
						elseif attackCounter == 57 then
							IEex_WriteByte(creatureData + 0x5636, 4)
						elseif attackCounter == 74 then
							IEex_WriteByte(creatureData + 0x5636, 5)
						end
--					end
				end

				if attackCounter == 5 then
					if manyshotAttacks > 0 then
						attackBonus = attackBonus - attackPenaltyIncrement * manyshotAttacks
						if manyshotAttacksMade > 0 then
--[[
							if bit.band(tempFlags, 0x8) == 0 then
								tempFlags = bit.bor(tempFlags, 0x8)
								IEex_WriteWord(creatureData + 0x9FA, tempFlags)
								IEex_WriteWord(creatureData + 0x9D6, IEex_ReadSignedWord(creatureData + 0x9D6, 0x0) - attackPenaltyIncrement * manyshotAttacks)
							end
--]]
--[[
							IEex_IterateActorEffects(targetID, function(eData)
								local theopcode = IEex_ReadDword(eData + 0x10)
								local thesavingthrow = IEex_ReadDword(eData + 0x40)
								if theopcode == 54 and bit.band(thesavingthrow, 0x10000000) > 0 then
									IEex_WriteDword(eData + 0x1C, 0 - attackPenaltyIncrement * manyshotAttacks)
								end
							end)
--]]
						end
					end
				elseif attackCounter == 7 then
					if manyshotAttacks > 0 then
						if manyshotAttacksMade > 0 then
--[[
							if bit.band(tempFlags, 0x8) > 0 then
								tempFlags = bit.band(tempFlags, 0xFFF7)
								IEex_WriteWord(creatureData + 0x9FA, tempFlags)
								IEex_WriteWord(creatureData + 0x9D6, IEex_ReadSignedWord(creatureData + 0x9D6, 0x0) + attackPenaltyIncrement * manyshotAttacks)
							end
--]]
--[[
							IEex_IterateActorEffects(targetID, function(eData)
								local theopcode = IEex_ReadDword(eData + 0x10)
								local thesavingthrow = IEex_ReadDword(eData + 0x40)
								if theopcode == 54 and bit.band(thesavingthrow, 0x10000000) > 0 then
									IEex_WriteDword(eData + 0x1C, 0)
								end
							end)
--]]
						end
					end
--]]
				elseif attackCounter == 57 then
					attackBonus = attackBonus - attackPenaltyIncrement * extraMainhandAttacksMade
				elseif attackCounter == 74 then
					attackBonus = attackBonus - attackPenaltyIncrement * extraAttacksMade
				end
			end
		end
	end
	attackCounter = IEex_ReadSignedByte(creatureData + 0x5622, 0x0)
	local sourceAlignment = IEex_ReadByte(creatureData + 0x35, 0x0)
	local outOfRange = false
--	if aboutToAttack or doAttackOfOpportunity then
	if IEex_IsSprite(actionTargetID, false) then
		if not isOffhandAttack then
			attackBonus = attackBonus + IEex_ReadSignedByte(creatureData + 0x9F8, 0x0)
		else
			attackBonus = attackBonus + IEex_ReadSignedByte(creatureData + 0x9FC, 0x0)
		end
		if hasSpecificCritBonuses then
			if not isOffhandAttack and weaponWrapper:isValid() then
				local weaponData = weaponWrapper:getData()
				local effectOffset = IEex_ReadDword(weaponData + 0x6A)
				local numGlobalEffects = IEex_ReadWord(weaponData + 0x70, 0x0)
				for i = 0, numGlobalEffects - 1, 1 do
					local offset = weaponData + effectOffset + i * 0x30
					local theopcode = IEex_ReadWord(offset, 0x0)
					local theresource = IEex_ReadLString(offset + 0x14, 8)
					local thesavingthrow = IEex_ReadDword(offset + 0x24)
					if theopcode == 500 and theresource == "MECRIT" and bit.band(thesavingthrow, 0x100000) > 0 then
						local theparameter1 = IEex_ReadDword(offset + 0x4)
						criticalHitBonus = criticalHitBonus + theparameter1
					end
				end
			elseif isOffhandAttack and offhandWrapperUsed and offhandWrapper:isValid() then
				local weaponData = offhandWrapper:getData()
				local effectOffset = IEex_ReadDword(weaponData + 0x6A)
				local numGlobalEffects = IEex_ReadWord(weaponData + 0x70, 0x0)
				for i = 0, numGlobalEffects - 1, 1 do
					local offset = weaponData + effectOffset + i * 0x30
					local theopcode = IEex_ReadWord(offset, 0x0)
					local theresource = IEex_ReadLString(offset + 0x14, 8)
					local thesavingthrow = IEex_ReadDword(offset + 0x24)
					if theopcode == 500 and theresource == "MECRIT" and bit.band(thesavingthrow, 0x100000) > 0 then
						local theparameter1 = IEex_ReadDword(offset + 0x4)
						criticalHitBonus = criticalHitBonus + theparameter1
					end
				end
			end
			if isLauncher and launcherWrapper:isValid() then
				local weaponData = launcherWrapper:getData()
				local effectOffset = IEex_ReadDword(weaponData + 0x6A)
				local numGlobalEffects = IEex_ReadWord(weaponData + 0x70, 0x0)
				for i = 0, numGlobalEffects - 1, 1 do
					local offset = weaponData + effectOffset + i * 0x30
					local theopcode = IEex_ReadWord(offset, 0x0)
					local theresource = IEex_ReadLString(offset + 0x14, 8)
					local thesavingthrow = IEex_ReadDword(offset + 0x24)
					if theopcode == 500 and theresource == "MECRIT" and bit.band(thesavingthrow, 0x100000) > 0 then
						local theparameter1 = IEex_ReadDword(offset + 0x4)
						criticalHitBonus = criticalHitBonus + theparameter1
					end
				end
			end
		end
		if IEex_IsSprite(actionTargetID, false) then
			if isLauncher then
				local weaponData = launcherWrapper:getData()
				range = range + IEex_ReadWord(weaponData + 0x90, 0x0)
			end
			if ex_pnp_ranged_penalty_without_precise_shot_to_avoid_hitting_ally and isRanged and bit.band(IEex_ReadDword(creatureData + 0x760), 0x10000) == 0 then
				local ids = {}
				if IEex_ReadDword(creatureData + 0x12) > 0 then
					ids = IEex_GetIDArea(targetID, 0x31)
				end
				local applyPreciseShotPenalty = false
				for k, currentID in ipairs(ids) do
					local currentShare = IEex_GetActorShare(currentID)
					if currentShare > 0 then
						local currentX = IEex_ReadDword(currentShare + 0x6)
						local currentY = IEex_ReadDword(currentShare + 0xA)
						local currentDistance = IEex_GetDistanceIsometric(actionTargetX, actionTargetY, currentX, currentY)
						local cea = IEex_CompareActorAllegiances(targetID, currentID)
						if cea == 1 and currentID ~= targetID and currentID ~= actionTargetID and currentDistance <= 100 then
							applyPreciseShotPenalty = true
						end
					end
				end
				if applyPreciseShotPenalty then
					attackBonus = attackBonus - 4
				end
			end
			local sourceVisualHeight = IEex_ReadDword(creatureData + 0xE)
			local targetVisualHeight = IEex_ReadDword(actionTargetData + 0xE)
			if math.abs(targetVisualHeight - sourceVisualHeight) > range * 20 + 40 then
				attackBonus = attackBonus - 20
				outOfRange = true
			end
			local alignment = IEex_ReadByte(creatureData + 0x35, 0x0)
			if bit.band(alignment, 0x3) == 0x3 and IEex_GetActorSpellState(actionTargetID, 1) then
				attackBonus = attackBonus - 2
			end
			IEex_IterateActorEffects(actionTargetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				local thespecial = IEex_ReadDword(eData + 0x48)
				if theopcode == 502 and theresource == "MEACVTYP" then
					if (theparameter2 == 2 and IEex_ReadByte(creatureData + 0x24, 0x0) == theparameter1) or (theparameter2 == 3 and IEex_ReadByte(creatureData + 0x25, 0x0) == theparameter1) or (theparameter2 == 4 and IEex_ReadByte(creatureData + 0x26, 0x0) == theparameter1) or (theparameter2 == 5 and bit.band(IEex_ReadDword(creatureData + 0x38), theparameter1) > 0) or (theparameter2 == 6 and IEex_ReadByte(creatureData + 0x27, 0x0) == theparameter1) or (theparameter2 == 7 and IEex_ReadByte(creatureData + 0x34, 0x0) == theparameter1) then
						attackBonus = attackBonus - thespecial
					elseif theparameter2 == 8 then
						if alignment == theparameter1 or bit.band(alignment, 0x3) == theparameter1 or bit.band(alignment, 0x30) == theparameter1 then
							attackBonus = attackBonus - thespecial
						end
					end
				end
			end)
		end
		ex_record_attack_stats_hidden_difference[targetID] = {attackBonus - ex_record_attack_stats[targetID][1], criticalHitBonus - ex_record_attack_stats[targetID][2]}
		IEex_WriteWord(creatureData + 0x936, criticalHitBonus)
		IEex_WriteWord(creatureData + 0x938, attackBonus)
		IEex_WriteWord(creatureData + 0x178E, criticalHitBonus)
		IEex_WriteWord(creatureData + 0x1790, attackBonus)
	end
--	IEex_EvaluatePersistentEffects(targetID)
	bitmapWrapper:free()
	weaponWrapper:free()
	if offhandWrapperUsed then
		offhandWrapper:free()
	end
	if isLauncher then
		launcherWrapper:free()
	end
	if doAttackOfOpportunity and not outOfRange then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["parameter1"] = ex_tra_55395,
["parent_resource"] = "USATTOPS",
["source_id"] = targetID
})
--[[
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 0,
["resource"] = "EFF_M17B",
["parent_resource"] = "USAPRBON",
["source_id"] = targetID
})
--]]
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 136,
["target"] = 2,
["timing"] = 1,
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(actionTargetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["savingthrow"] = 0x10000,
["special"] = (0 - opportunityAttackBonus),
["resource"] = "MEWHIRLA",
["parent_resource"] = "USATTOPP",
["source_id"] = targetID
})
	end
end

function IEex_BitmapPrint(bitmapRES)
	local creatureData = IEex_GSS()
	local resWrapper = IEex_DemandRes(bitmapRES, "BMP")
	if resWrapper:isValid() then
		local bitmapData = resWrapper:getData()
		local currentColor = IEex_GetBitmapPixelColor(bitmapData, math.floor(IEex_ReadDword(creatureData + 0x6) / 16), math.floor(IEex_ReadDword(creatureData + 0xA) / 12))
		local currentIndex = IEex_GetBitmapPixelIndex(bitmapData, math.floor(IEex_ReadDword(creatureData + 0x6) / 16), math.floor(IEex_ReadDword(creatureData + 0xA) / 12))
		local currentLighting = IEex_ReadDword(creatureData + 0x4D6A)
		IEex_DS(IEex_ToHex(currentColor, 0, false) .. ", " .. currentIndex .. ", " .. currentLighting)
	end
	resWrapper:free()
end

function IEex_GetBitmapPixelColor(bitmapData, x, y)
	local fileSize = IEex_ReadDword(bitmapData + 0x2)
	local dataOffset = IEex_ReadDword(bitmapData + 0xA)
	local bitmapX = IEex_ReadDword(bitmapData + 0x12)
	local bitmapY = IEex_ReadDword(bitmapData + 0x16)
	local bitCount = IEex_ReadWord(bitmapData + 0x1C, 0x0)
	y = bitmapY - y - 1
	if x < 0 or x >= bitmapX or y < 0 or y >= bitmapY then
		return -1
	end
	if bitCount == 4 then
		local padding = 4 - (math.ceil(bitmapX / 2) % 4)
		if padding == 4 then
			padding = 0
		end
		local trueBitmapX = math.ceil(bitmapX / 2) + padding
		local current = IEex_ReadByte(bitmapData + dataOffset + y * trueBitmapX + math.floor(x / 2), 0x0)
		if x % 2 == 0 then
			return bit.band(IEex_ReadDword(bitmapData + 0x36 + math.floor(current / 16) * 0x4), 0xFFFFFF)
		else
			return bit.band(IEex_ReadDword(bitmapData + 0x36 + (current % 16) * 0x4), 0xFFFFFF)
		end
	elseif bitCount == 8 then
		local padding = 4 - (bitmapX % 4)
		if padding == 4 then
			padding = 0
		end
		local trueBitmapX = bitmapX + padding
		local current = IEex_ReadByte(bitmapData + dataOffset + y * trueBitmapX + x, 0x0)
		return bit.band(IEex_ReadDword(bitmapData + 0x36 + current * 0x4), 0xFFFFFF)
	else
		return -1
	end
end

function IEex_GetBitmapPixelIndex(bitmapData, x, y)
	local fileSize = IEex_ReadDword(bitmapData + 0x2)
	local dataOffset = IEex_ReadDword(bitmapData + 0xA)
	local bitmapX = IEex_ReadDword(bitmapData + 0x12)
	local bitmapY = IEex_ReadDword(bitmapData + 0x16)
	local bitCount = IEex_ReadWord(bitmapData + 0x1C, 0x0)
	y = bitmapY - y - 1
	if x < 0 or x >= bitmapX or y < 0 or y >= bitmapY then
		return -1
	end
	if bitCount == 4 then
		local padding = 4 - (math.ceil(bitmapX / 2) % 4)
		if padding == 4 then
			padding = 0
		end
		local trueBitmapX = math.ceil(bitmapX / 2) + padding
		local current = IEex_ReadByte(bitmapData + dataOffset + y * trueBitmapX + math.floor(x / 2), 0x0)
		if x % 2 == 0 then
			return (math.floor(current / 16))
		else
			return (current % 16)
		end
	elseif bitCount == 8 then
		local padding = 4 - (bitmapX % 4)
		if padding == 4 then
			padding = 0
		end
		local trueBitmapX = bitmapX + padding
		local current = IEex_ReadByte(bitmapData + dataOffset + y * trueBitmapX + x, 0x0)
		return current
	else
		return -1
	end
end

function MENOTEL(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local sourceData = IEex_GetActorShare(sourceID)
	local sourceX = IEex_ReadDword(sourceData + 0x6)
	local sourceY = IEex_ReadDword(sourceData + 0xA)
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	local targetIDX = IEex_ReadDword(creatureData + 0x6)
	local targetIDY = IEex_ReadDword(creatureData + 0xA)
	local disableTeleport = false

	local areaData = IEex_ReadDword(creatureData + 0x12)
	if areaData <= 0 then return end
	local areaType = IEex_ReadWord(areaData + 0x40, 0x0)
	if bit.band(areaType, 0x800) > 0 then
		disableTeleport = true
	else
		local areaRES = IEex_ReadLString(areaData, 8)
		if ex_specific_teleport_zone[areaRES] ~= nil then
			local noTeleportMapWrapper = IEex_DemandRes(areaRES .. "NT", "BMP")
			if noTeleportMapWrapper:isValid() then
				local noTeleportMapData = noTeleportMapWrapper:getData()
				local currentZone = IEex_GetBitmapPixelIndex(noTeleportMapData, math.floor(sourceX / 16), math.floor(sourceY / 12))
				local destinationZone = IEex_GetBitmapPixelIndex(noTeleportMapData, math.floor(targetX / 16), math.floor(targetY / 12))
				if currentZone ~= destinationZone then
					disableTeleport = true
				end
			end
			noTeleportMapWrapper:free()
		end
	end
	if disableTeleport then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["resource"] = IEex_ReadLString(effectData + 0x90, 8),
["source_id"] = sourceID
})
	end
end

function METELEFI(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local sourceX = IEex_ReadDword(effectData + 0x7C)
	local sourceY = IEex_ReadDword(effectData + 0x80)
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local done = false
	local deltaX = 0
	local deltaY = 0
	while done == false do
		deltaX = (math.random(parameter1 + 1) - 1) * 2 - parameter1
		deltaY = (math.random(parameter1 + 1) - 1) * 2 - parameter1
		if (deltaX * deltaX + deltaY * deltaY <= parameter1 * parameter1) then
			done = true
		end
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = targetX + deltaX,
["target_y"] = targetY + deltaY,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
end

function MERECALL(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local sourceData = IEex_GetActorShare(sourceID)
	if IEex_ReadDword(creatureData + 0x12) ~= IEex_ReadDword(sourceData + 0x12) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local sourceX, sourceY = IEex_GetActorLocation(sourceID)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["target_x"] = sourceX,
["target_y"] = sourceY,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
end

function METRANST(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, true) then return end
	local sourceData = IEex_GetActorShare(sourceID)
	if IEex_ReadDword(creatureData + 0x12) ~= IEex_ReadDword(sourceData + 0x12) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local sourceX, sourceY = IEex_GetActorLocation(sourceID)
	local targetX, targetY = IEex_GetActorLocation(targetID)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	IEex_IterateProjectiles(targetID, -1, function(projectileData)
		local projectileType = IEex_ProjectileType[IEex_ReadWord(projectileData + 0x6E, 0x0) + 1]
		local doSwitchProjectile = true
		if projectileType == 6 then
			if IEex_ReadByte(projectileData + 0x2B6, 0x0) > 0 then
				doSwitchProjectile = false
			end
		elseif projectileType == 8 then
			if IEex_ReadByte(projectileData + 0x2A8, 0x0) > 0 then
				doSwitchProjectile = false
			end
		end
		if doSwitchProjectile then
			local projectileSourceID = IEex_ReadDword(projectileData + 0x72)
			local projectileTargetID = IEex_ReadDword(projectileData + 0x76)
			if projectileSourceID == sourceID then
				IEex_WriteDword(projectileData + 0x72, targetID)
			elseif projectileSourceID == targetID then
				IEex_WriteDword(projectileData + 0x72, sourceID)
			end
			if projectileTargetID == sourceID then
				IEex_WriteDword(projectileData + 0x76, targetID)
			elseif projectileTargetID == targetID then
				IEex_WriteDword(projectileData + 0x76, sourceID)
			end
		end
	end)
	local sourceVisualHeight = IEex_ReadDword(sourceData + 0xE)
	IEex_WriteDword(sourceData + 0xE, IEex_ReadDword(creatureData + 0xE))
	IEex_WriteDword(creatureData + 0xE, sourceVisualHeight)
	local sourceHeight = IEex_ReadSignedWord(sourceData + 0x720, 0x0)
	IEex_WriteWord(sourceData + 0x720, IEex_ReadSignedWord(creatureData + 0x720, 0x0))
	IEex_WriteWord(creatureData + 0x720, sourceHeight)
	local sourceVelocity = IEex_ReadSignedWord(sourceData + 0x722, 0x0)
	IEex_WriteWord(sourceData + 0x722, IEex_ReadSignedWord(creatureData + 0x722, 0x0))
	IEex_WriteWord(creatureData + 0x722, sourceVelocity)
	local sourceAccel = IEex_ReadSignedWord(sourceData + 0x724, 0x0)
	IEex_WriteWord(sourceData + 0x724, IEex_ReadSignedWord(creatureData + 0x724, 0x0))
	IEex_WriteWord(creatureData + 0x724, sourceAccel)
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 184,
["target"] = 2,
["timing"] = 0,
["parameter2"] = 1,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 184,
["target"] = 2,
["timing"] = 0,
["parameter2"] = 1,
["parent_resource"] = parent_resource,
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["target_x"] = targetX,
["target_y"] = targetY,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["target_x"] = sourceX,
["target_y"] = sourceY,
["parent_resource"] = parent_resource,
["source_id"] = targetID
})
end

function IEex_JumpActorToPoint(actorID, pointX, pointY, bSendSpriteUpdateMessage)
	if not IEex_IsSprite(actorID, true) then return end
	if bSendSpriteUpdateMessage == nil then bSendSpriteUpdateMessage = true end 
	IEex_Call(0x745950, {bSendSpriteUpdateMessage and 1 or 0, pointY, pointX}, IEex_GetActorShare(actorID), 0x0)
end

function MESETZ(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	IEex_WriteDword(creatureData + 0xE, parameter1 * -1)
end

function MEWINGBU(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MEWINGBU", 5) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local sourceData = IEex_GetActorShare(sourceID)
	if IEex_GetActorSpellState(targetID, 212) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	if parameter1 <= 0 then return end
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	if parameter2 == 4 and not IEex_IsSprite(sourceID, false) then return end
	local timeSlowed, targetNotSlowed = IEex_CheckGlobalEffectOnActor(targetID, 0x2)
	if IEex_GetGameTick() % ex_time_slow_speed_divisor ~= 0 then
		if timeSlowed and not targetNotSlowed then return end
	end
	local parameter4 = IEex_ReadDword(effectData + 0x60)
	local special = IEex_ReadDword(effectData + 0x44)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if bit.band(savingthrow, 0x100000) > 0 and IEex_IsFlying(targetID) then return end
	if bit.band(savingthrow, 0x200000) > 0 then
		local animationData = IEex_ReadDword(creatureData + 0x50F0)
		if animationData > 0 then
			parameter1 = parameter1 - IEex_ReadDword(animationData + 0x10)
			if parameter1 < 0 then
				parameter1 = 0
			end
			IEex_WriteDword(effectData + 0x18, parameter1)
			savingthrow = bit.band(savingthrow, 0xFFDFFFFF)
			IEex_WriteDword(effectData + 0x3C, savingthrow)
		end
	end
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
	local sourceX = targetX
	local sourceY = targetY
	local disableTeleport = false
	local areaData = IEex_ReadDword(creatureData + 0x12)
	local areaRES = ""
	local areaX = 32767
	local areaY = 32767
	if areaData > 0 then
		areaRES = IEex_ReadLString(areaData, 8)
		areaX = IEex_ReadDword(areaData + 0x54C)
		areaY = IEex_ReadDword(areaData + 0x550)
		local areaType = IEex_ReadWord(areaData + 0x40, 0x0)
		if bit.band(areaType, 0x800) > 0 then
			disableTeleport = true
--[[
		else
			if areaRES == "AR4102" and (targetX >= 400 and targetX <= 970 and targetY >= 1030 and targetY <= 1350) then
				disableTeleport = true
			end
--]]
		end
	end
	if parameter4 == 0 then
		IEex_WriteDword(effectData + 0x60, 1)
		if (parameter2 == 5 or parameter2 == 6) and sourceData > 0 then
			IEex_WriteDword(effectData + 0x7C, IEex_ReadDword(sourceData + 0x6))
			IEex_WriteDword(effectData + 0x80, IEex_ReadDword(sourceData + 0xA))
		end
	end

	if parameter2 == 2 or parameter2 == 4 then
		if sourceData > 0 then
			sourceX = IEex_ReadDword(sourceData + 0x6)
			sourceY = IEex_ReadDword(sourceData + 0xA)
		end
	elseif parameter2 == 1 or parameter2 == 3 then
		sourceX = IEex_ReadDword(effectData + 0x84)
		sourceY = IEex_ReadDword(effectData + 0x88)
	elseif parameter2 == 5 or parameter2 == 6 then
		sourceX = IEex_ReadDword(effectData + 0x7C)
		sourceY = IEex_ReadDword(effectData + 0x80)
	end
	if parameter2 == 4 then
		local sizeSpaceX = IEex_ReadDword(IEex_ReadDword(sourceData + 0x50F0) + 0x10) + IEex_ReadDword(IEex_ReadDword(creatureData + 0x50F0) + 0x10)
		local sizeSpaceY = IEex_ReadDword(IEex_ReadDword(sourceData + 0x50F0) + 0x14) + IEex_ReadDword(IEex_ReadDword(creatureData + 0x50F0) + 0x14)
		local destinationX = IEex_ReadDword(sourceData + 0x556E)
		local destinationY = IEex_ReadDword(sourceData + 0x5572)
		if destinationX > 0 and destinationY > 0 and IEex_ReadDword(sourceData + 0x4BE) ~= targetID then
			local orientation = IEex_ReadByte(sourceData + 0x5380, 0x0)
			if orientation >= 2 and orientation <= 6 then
				sourceX = sourceX + sizeSpaceX
			elseif orientation >= 10 and orientation <= 14 then
				sourceX = sourceX - sizeSpaceX
			end
			if orientation >= 6 and orientation <= 10 then
				sourceY = sourceY + sizeSpaceY
			elseif orientation <= 2 or orientation >= 14 then
				sourceY = sourceY - sizeSpaceY
			end
--[[
			if destinationX >= sourceX then
				sourceX = sourceX - sizeSpaceX
			else
				sourceX = sourceX + sizeSpaceX
			end
			if destinationY >= sourceY then
				sourceY = sourceY - sizeSpaceY
			else
				sourceY = sourceY + sizeSpaceY
			end
--]]
		else
			if targetX >= sourceX then
				sourceX = sourceX + sizeSpaceX
			else
				sourceX = sourceX - sizeSpaceX
			end
			if targetY >= sourceY then
				sourceY = sourceY + sizeSpaceY
			else
				sourceY = sourceY - sizeSpaceY
			end
		end
	end
	local distX = targetX - sourceX
	local distY = targetY - sourceY
--[[
	if parameter2 == 4 then
		local sizeSpaceX = IEex_ReadDword(IEex_ReadDword(sourceData + 0x50F0) + 0x10) + IEex_ReadDword(IEex_ReadDword(creatureData + 0x50F0) + 0x10)
		local sizeSpaceY = IEex_ReadDword(IEex_ReadDword(sourceData + 0x50F0) + 0x14) + IEex_ReadDword(IEex_ReadDword(creatureData + 0x50F0) + 0x14)

		if distX >= 0 then
			distX = distX - sizeSpaceX
			if distX < 0 then
				distX = 0
			end
		else
			distX = distX + sizeSpaceX
			if distX > 0 then
				distX = 0
			end
		end
		if distY >= 0 then
			distY = distY - sizeSpaceY
			if distY < 0 then
				distY = 0
			end
		else
			distY = distY + sizeSpaceY
			if distY > 0 then
				distY = 0
			end
		end

	end
--]]
	local dist = math.floor((distX ^ 2 + distY ^ 2) ^ .5)
	local deltaX = 0
	local deltaY = 0
	if dist ~= 0 then
		deltaX = math.floor(parameter1 * distX / dist)
		deltaY = math.floor(parameter1 * distY / dist)
	end
	if parameter2 == 3 or parameter2 == 4 or parameter2 == 6 then
		if math.abs(deltaX) > math.abs(distX) then
			deltaX = distX
		end
		if math.abs(deltaY) > math.abs(distY) then
			deltaY = distY
		end
		deltaX = deltaX * -1
		deltaY = deltaY * -1
	end
	local finalX = targetX + deltaX
	local finalY = targetY + deltaY
	if IEex_IsGamePaused() then
		finalX = targetX
		finalY = targetY
	end
	if finalX < 0 then
		finalX = 1
	elseif finalX >= areaX then
		finalX = areaX - 1
	end
	if finalY < 0 then
		finalY = 1
	elseif finalY >= areaY then
		finalY = areaY - 1
	end
	local height = IEex_ReadSignedWord(creatureData + 0x720, 0x0)
	local destinationHeight = 0
	local collideWithWall = false
	if ex_specific_teleport_zone[areaRES] ~= nil then
		local noTeleportMapWrapper = IEex_DemandRes(areaRES .. "NT", "BMP")
		if noTeleportMapWrapper:isValid() then
			local noTeleportMapData = noTeleportMapWrapper:getData()
			local currentZone = IEex_GetBitmapPixelIndex(noTeleportMapData, math.floor(targetX / 16), math.floor(targetY / 12))
			local destinationZone = IEex_GetBitmapPixelIndex(noTeleportMapData, math.floor(finalX / 16), math.floor(finalY / 12))
			if currentZone ~= destinationZone then
				disableTeleport = true
			end
		end
		noTeleportMapWrapper:free()
	end
	if ex_specific_floor_height[areaRES] ~= nil then


		local heightMap2Wrapper = IEex_DemandRes(areaRES .. "H2", "BMP")
		if heightMap2Wrapper:isValid() then
			local heightMap2Data = heightMap2Wrapper:getData()
			local specificFloorHeight = IEex_GetBitmapPixelColor(heightMap2Data, math.floor(finalX / 16), math.floor(finalY / 12))

			if ex_specific_floor_height[areaRES][specificFloorHeight] ~= nil then
				destinationHeight = ex_specific_floor_height[areaRES][specificFloorHeight]
			end
			if height < 0 and destinationHeight > math.floor(height / 2) then
				collideWithWall = true
--				finalX = targetX
--				finalY = targetY
			elseif destinationHeight < math.floor(height / 2) then
				IEex_WriteByte(creatureData + 0x9DC, 1)
			end
		end
		heightMap2Wrapper:free()
	end
	local searchMapWrapper = IEex_DemandRes(areaRES .. "SR", "BMP")
	if searchMapWrapper:isValid() then
		local searchMapData = searchMapWrapper:getData()
		local destinationAccessibility = ex_default_terrain_table_1[IEex_GetBitmapPixelIndex(searchMapData, math.floor(finalX / 16), math.floor(finalY / 12)) + 1] 
		if destinationAccessibility == -1 and destinationHeight >= 0 then
			collideWithWall = true
		end
	end
	searchMapWrapper:free()
	if collideWithWall and (parameter2 == 1 or parameter2 == 2 or parameter2 == 5) and (height < 0 or IEex_ReadByte(creatureData + 0x9DC, 0x0) == 0) and not IEex_GetActorSpellState(targetID, 182) and not IEex_GetActorSpellState(targetID, 189) then
		local damageDice = math.floor((parameter1 - 10) / 3)
		if damageDice > 100 then
			damageDice = 100
		end
		if damageDice > 0 then
			parameter1 = 0
			IEex_WriteDword(effectData + 0x18, 0)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = 0x600 + damageDice * 0x10000,
["savingthrow"] = 0x4090000,
["resource"] = "EXDAMAGE",
["parent_resource"] = "MEWALDMG",
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["resource"] = "MEWALDMG",
["source_target"] = targetID,
["source_id"] = sourceID
})
		end
	elseif height == 0 or special > 0 then
		IEex_WriteDword(effectData + 0x18, parameter1 + special)
	end
	if not disableTeleport then
		if ex_ghostwalk_dest["" .. targetID] ~= nil and ex_ghostwalk_dest["" .. targetID][1] == targetX and ex_ghostwalk_dest["" .. targetID][2] == targetY then
			ex_ghostwalk_dest["" .. targetID][1] = finalX
			ex_ghostwalk_dest["" .. targetID][2] = finalY
		end
		IEex_PreventMovingAttacksOfOpportunity(targetID, 10)
		IEex_JumpActorToPoint(targetID, finalX, finalY, true)
--[[
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = finalX,
["target_y"] = finalY,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
--]]
	end
end

function MEPSTAIR(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	if parameter1 <= 0 then return end
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local special = IEex_ReadDword(effectData + 0x44)
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - time_applied) / 15)
	end
	if targetY < parameter2 then
		duration = math.ceil((parameter2 - targetY) / 100)
		parameter1 = parameter1 * math.ceil((parameter2 - targetY) / 100)
	end
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter1"] = parameter1,
["parameter2"] = 3,
["special"] = special,
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = targetX - 500,
["target_y"] = targetY + 1000,
["resource"] = "MEWINGBU",
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 419,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter2"] = 1,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
end

function MEREND(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local special = IEex_ReadDword(effectData + 0x44)
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - time_applied) / 15)
	end
	local canRend = false
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter1 = IEex_ReadDword(eData + 0x1C)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local thespecial = IEex_ReadDword(eData + 0x48)
		local thesourceID = IEex_ReadDword(eData + 0x110)
		if theopcode == 0 and bit.band(thesavingthrow, 0x400000) > 0 then
			if thesourceID == targetID and (thespecial ~= special or special == -1 or thespecial == -1) then
				canRend = true
			end
			IEex_WriteDword(eData + 0x114, 1)
		end
	end)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	if canRend then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
	else
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["savingthrow"] = 0x400000,
["special"] = special,
["parent_resource"] = parent_resource,
["source_id"] = targetID
})
	end
end

function MERECTSP(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - time_applied) / 15)
	end
	local sourceX = IEex_ReadDword(effectData + 0x7C)
	local sourceY = IEex_ReadDword(effectData + 0x80)
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	local sourceData = IEex_GetActorShare(sourceID)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if sourceData > 0 and bit.band(savingthrow, 0x200000) == 0 then
		sourceX = IEex_ReadDword(sourceData + 0x6)
		sourceY = IEex_ReadDword(sourceData + 0xA)
		if targetID ~= sourceID then
			targetX = IEex_ReadDword(creatureData + 0x6)
			targetY = IEex_ReadDword(creatureData + 0xA)
		end
	end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	if parameter1 <= 0 then return end
	local length = IEex_ReadWord(effectData + 0x44, 0x0)
	local width = IEex_ReadWord(effectData + 0x46, 0x0)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local angle = key_angles[IEex_ReadDword(effectData + 0x5C) + 1]
	local distX = targetX - sourceX
	local distY = targetY - sourceY
	local dist = math.floor((distX ^ 2 + distY ^ 2) ^ .5)
	local deltaX = 0
	local deltaY = 0
	local cornerDeltaX = 0
	local cornerDeltaY = 0
	if bit.band(savingthrow, 0x200000) > 0 then
		deltaX = math.floor(length * math.cos(math.rad(angle)))
		deltaY = math.floor(length * math.sin(math.rad(angle)))
		cornerDeltaX = math.floor(width * math.sin(math.rad(angle)))
		cornerDeltaY = math.floor(width * math.cos(math.rad(angle))) * -1
	elseif dist ~= 0 then
		deltaX = math.floor(length * distX / dist)
		deltaY = math.floor(length * distY / dist)
		cornerDeltaX = math.floor(width * distY / dist)
		cornerDeltaY = math.floor(width * distX / dist) * -1
	end
	local slope = 0x7FFFFFFF
	local cornerSlope = 0x7FFFFFFF
	if deltaX ~= 0 then
		slope = math.abs(deltaY / deltaX)
	end
	if cornerDeltaX ~= 0 then
		cornerSlope = math.abs(cornerDeltaY / cornerDeltaX)
	end
	local finalX = sourceX + deltaX
	local finalY = sourceY + deltaY
	local corners = {{sourceX + cornerDeltaX, sourceY + cornerDeltaY, -1}, {sourceX - cornerDeltaX, sourceY - cornerDeltaY, -1}, {finalX + cornerDeltaX, finalY + cornerDeltaY, -1}, {finalX - cornerDeltaX, finalY - cornerDeltaY, -1}, }
	local highestXCorner = {-65536, -65536}
	local highestYCorner = {-65536, -65536}
	local lowestXCorner = {65535, 65535}
	local lowestYCorner = {65535, 65535}
	for k, v in ipairs(corners) do
		if v[1] > highestXCorner[1] then
			highestXCorner = v
		end
		if v[2] > highestYCorner[2] then
			highestYCorner = v
		end
		if v[1] < lowestXCorner[1] then
			lowestXCorner = v
		end
		if v[2] < lowestYCorner[2] then
			lowestYCorner = v
		end
	end
	if math.abs(lowestYCorner[1] - lowestXCorner[1]) == math.abs(deltaX) then
		highestXCorner[3] = cornerSlope
		highestYCorner[3] = cornerSlope
		lowestXCorner[3] = slope
		lowestYCorner[3] = cornerSlope
	else
		highestXCorner[3] = slope
		highestYCorner[3] = slope
		lowestXCorner[3] = cornerSlope
		lowestYCorner[3] = slope
	end
	IEex_IterateIDs(IEex_ReadDword(creatureData + 0x12), 0x31, function(currentID)
		local currentShare = IEex_GetActorShare(currentID)
		if IEex_IsSprite(currentID, false) and IEex_ReadByte(currentShare + 0x838, 0x0) == 0 then
			local currentX, currentY = IEex_GetActorLocation(currentID)
			local inAOE = true
			if currentX < lowestXCorner[1] or currentX > highestXCorner[1] or currentY < lowestYCorner[2] or currentY > highestYCorner[2] then
				inAOE = false
			else
				if highestYCorner[1] - currentX ~= 0 then
					local currentHYSlope = math.abs((currentY - highestYCorner[2]) / (highestYCorner[1] - currentX))
					if currentX < highestYCorner[1] then
						if currentHYSlope < highestYCorner[3] then
							inAOE = false
						end
					else
						if (highestYCorner[3] == slope and currentHYSlope < cornerSlope) or (highestYCorner[3] == cornerSlope and currentHYSlope < slope) then
							inAOE = false
						end
					end
				end

				if lowestXCorner[1] - currentX ~= 0 and currentY < lowestXCorner[2] then
					local currentLXSlope = math.abs((currentY - lowestXCorner[2]) / (lowestXCorner[1] - currentX))
					if currentLXSlope > lowestXCorner[3] then
						inAOE = false
					end
				end
				if highestXCorner[1] - currentX ~= 0 and currentY < highestXCorner[2] then
					local currentHXSlope = math.abs((currentY - highestXCorner[2]) / (highestXCorner[1] - currentX))
					if currentHXSlope > highestXCorner[3] then
						inAOE = false
					end
				end
				if inAOE then
					if currentID ~= sourceID or bit.band(savingthrow, 0x100000) == 0 then
						IEex_ApplyEffectToActor(currentID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["source_x"] = sourceX,
["source_y"] = sourceY,
["target_x"] = currentX - deltaX,
["target_y"] = currentY - deltaY,
["resource"] = IEex_ReadLString(effectData + 0x18, 8),
["casterlvl"] = casterlvl,
["internal_flags"] = internalFlags,
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
					end
				end
			end
		end
	end)
end

function METELMOV(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "METELMOV", 5) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local special = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
	local destinationX = IEex_ReadDword(creatureData + 0x556E)
	local destinationY = IEex_ReadDword(creatureData + 0x5572)
	local action = IEex_ReadWord(creatureData + 0x476, 0x0)
	local actionX = IEex_ReadDword(creatureData + 0x540)
	local actionY = IEex_ReadDword(creatureData + 0x544)
	local disableTeleport = false
	local isOutdoors = false
	local isNight = false
	local areaData = IEex_ReadDword(creatureData + 0x12)
	if areaData <= 0 then return end
	local areaType = IEex_ReadWord(areaData + 0x40, 0x0)
	local areaRES = IEex_ReadLString(areaData, 8)
	if bit.band(areaType, 0x1) > 0 then
		isOutdoors = true
	end
	if bit.band(areaType, 0x40) > 0 or IEex_IsNight() then
		isNight = true
	end
	if bit.band(areaType, 0x800) > 0 then
		disableTeleport = true
	else
--[[
		if areaRES == "AR4102" and ((targetX >= 400 and targetX <= 970 and targetY >= 1030 and targetY <= 1350) or (destinationX >= 400 and destinationX <= 970 and destinationY >= 1030 and destinationY <= 1350)) then
			disableTeleport = true
		end
--]]
		if ex_specific_teleport_zone[areaRES] ~= nil then
			local noTeleportMapWrapper = IEex_DemandRes(areaRES .. "NT", "BMP")
			if noTeleportMapWrapper:isValid() then
				local noTeleportMapData = noTeleportMapWrapper:getData()
				local currentZone = IEex_GetBitmapPixelIndex(noTeleportMapData, math.floor(targetX / 16), math.floor(targetY / 12))
				local destinationZone = IEex_GetBitmapPixelIndex(noTeleportMapData, math.floor(destinationX / 16), math.floor(destinationY / 12))
				if currentZone ~= destinationZone then
					disableTeleport = true
				end
			end
			noTeleportMapWrapper:free()
		end
	end
--[[
	if destinationX <= 0 and destinationY <= 0 then
		destinationX = targetX
		destinationY = targetY
	end
--]]
	if bit.band(savingthrow, 0x10000) > 0 then
		
		local lightMapWrapper = IEex_DemandRes(areaRES .. "LM", "BMP")
		if lightMapWrapper:isValid() then
			local lightMapData = lightMapWrapper:getData()
			local currentBrightness = math.floor(IEex_GetBitmapPixelColor(lightMapData, math.floor(targetX / 16), math.floor(targetY / 12)) / 0x10000)
			local destinationBrightness = math.floor(IEex_GetBitmapPixelColor(lightMapData, math.floor(destinationX / 16), math.floor(destinationY / 12)) / 0x10000)
			if not isOutdoors then
				currentBrightness = currentBrightness - 40
				destinationBrightness = destinationBrightness - 40
			elseif isNight then
				currentBrightness = currentBrightness - 80
				destinationBrightness = destinationBrightness - 80
			end
			if currentBrightness > ex_shadowstep_brightness_max or destinationBrightness > ex_shadowstep_brightness_max then
				disableTeleport = true
			end
			lightMapWrapper:free()
		end
	end
	if disableTeleport == false then
		if (destinationX > 0 or destinationY > 0) then
--			IEex_EvaluatePersistentEffects(targetID)
--[[
			if special == 1 then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 59,
["parent_resource"] = "USTELMOV",
["source_id"] = targetID
})
			end
--]]
--			local newDirection = IEex_GetActorRequiredDirection(targetID, destinationX, destinationY)
			IEex_PreventMovingAttacksOfOpportunity(targetID, 10)
			IEex_JumpActorToPoint(targetID, destinationX, destinationY, true)
--[[
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = destinationX,
["target_y"] = destinationY,
["parent_resource"] = "USTELMOV",
["source_id"] = targetID
})
--]]
--[[
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = newDirection,
["resource"] = "MEFACE",
["parent_resource"] = "USTELMOV",
["source_id"] = targetID
})
--]]
--			IEex_WriteByte(creatureData + 0x537E, newDirection)
--			IEex_WriteByte(creatureData + 0x5380, (newDirection + 1) % 16)
--[[
			if special == 1 then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 60,
["parent_resource"] = "USTELMOV",
["source_id"] = targetID
})
			end
--]]
		end
	end
end

function MEMSWRD(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	local summonerID = IEex_GetActorSummonerID(sourceID)
	if not IEex_IsSprite(summonerID, false) then return end
	local summonerData = IEex_GetActorShare(summonerID)
	local summonerActionID = IEex_ReadWord(summonerData + 0x476, 0x0)
	local targetID = IEex_ReadDword(summonerData + 0x4BE)
	if summonerActionID == 3 or summonerActionID == 94 or summonerActionID == 98 or summonerActionID == 105 or summonerActionID == 134 then
--		IEex_WriteWord(creatureData + 0x476, 22)
--		IEex_WriteDword(creatureData + 0x4BE, targetID)
		local summonerSequence = IEex_ReadByte(summonerData + 0x50F4, 0x0)
		IEex_WriteByte(creatureData + 0x50F4, summonerSequence)
		local summonerAnimationData = IEex_ReadDword(summonerData + 0x50F0)
		local attackAnimationFrameOffset = 0
		if summonerSequence == 11 then
			attackAnimationFrameOffset = 0x694
		elseif summonerSequence == 12 then
			attackAnimationFrameOffset = 0x76E
		elseif summonerSequence == 13 then
			attackAnimationFrameOffset = 0x848
		else
			return
		end
		local attackAnimationFrame = IEex_ReadSignedWord(summonerAnimationData + attackAnimationFrameOffset, 0x0)
		if attackAnimationFrame == 1 then
--[[
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 138,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 0,
["parent_resource"] = "USMSWRDA",
["source_id"] = sourceID
})
--]]
		end
		IEex_SetAttackAnimationFrame(creatureData, attackAnimationFrame)
	end
end

function MEBLINK(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local special = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	if math.random(100) <= special then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theopcode == 288 and theparameter2 == 2 and theparent_resource == parent_resource then
				IEex_WriteDword(eData + 0x20, 182)
			elseif theopcode == 66 and theparent_resource == parent_resource then
				IEex_WriteDword(eData + 0x1C, parameter1)
			end
		end)
	else
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theopcode == 288 and theparameter2 == 182 and theparent_resource == parent_resource then
				IEex_WriteDword(eData + 0x20, 2)
			elseif theopcode == 66 and theparent_resource == parent_resource then
				IEex_WriteDword(eData + 0x1C, 0)
			end
		end)
	end
end

ex_ghostwalk_dest = {}
ex_ghostwalk_direction = {}
ex_ghostwalk_area = {}
ex_ghostwalk_offsets = {{-20, -20}, {0, -20}, {20, -20}, {20, 0}, {20, 20}, {0, 20}, {-20, 20}, {-20, 0}, {-10, -30}, {10, -30}, {30, -10}, {30, 10}, {10, 30}, {-10, 30}, {-30, 10}, {-30, -10}}
ex_ghostwalk_offsets_taken = {}
ex_current_ghostwalk_target_offset = {}
ex_ghostwalk_positions = {}
ex_ghostwalk_actors = {}
ex_previous_ghostwalk_tick = {}
function MEGHOSTW(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if IEex_ReadDword(effectData + 0x10C) <= 0 or bit.band(internalFlags, 0x10) == 0 then
		IEex_WriteDword(effectData + 0x10C, sourceID)
		IEex_WriteDword(effectData + 0xD4, bit.bor(internalFlags, 0x10))
		ex_ghostwalk_dest["" .. sourceID] = nil
		ex_ghostwalk_area["" .. sourceID] = nil
	end
	local timeSlowed, targetNotSlowed = IEex_CheckGlobalEffectOnActor(sourceID, 0x2)
	if IEex_GetGameTick() % ex_time_slow_speed_divisor ~= 0 then
		if timeSlowed and not targetNotSlowed then return end
	end
	if IEex_InCutsceneMode() and not IEex_IsPartyMember(sourceID) then return end
	local actionID = IEex_ReadWord(creatureData + 0x476, 0x0)
	if actionID == 105 or actionID == 134 then
		actionID = 3
		IEex_WriteWord(creatureData + 0x476, actionID)
	end
	local actionX = IEex_ReadDword(creatureData + 0x540)
	local actionY = IEex_ReadDword(creatureData + 0x544)
	local destinationX = IEex_ReadDword(creatureData + 0x556E)
	local destinationY = IEex_ReadDword(creatureData + 0x5572)
	local targetID = IEex_ReadDword(creatureData + 0x4BE)
	if actionID == 95 or actionID == 97 then
		destinationX = actionX
		destinationY = actionY
		ex_ghostwalk_dest["" .. sourceID] = nil
	elseif IEex_IsSprite(targetID, false) then
		actionX, actionY = IEex_GetActorLocation(targetID)
		destinationX = actionX
		destinationY = actionY
--]]
	end
	if ((actionID == 95 or actionID == 97 or actionID == 192) and IEex_CheckActorLOS(sourceID, actionX, actionY)) or actionID == 114 or actionID == 34 or (actionID == 31 and destinationX <= 0) then return end
--	if IEex_CheckForInfiniteLoop(sourceID, IEex_GetGameTick(), "MEGHOSTW", 0) then return end
--	if not IEex_GetActorSpellState(sourceID, 184) and not IEex_GetActorSpellState(sourceID, 189) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local parameter4 = IEex_ReadDword(effectData + 0x60)
--	local movementRate = IEex_ReadByte(creatureData + 0x72EA, 0x0)
	local movementRate = 9
	local animationSequence = IEex_ReadByte(creatureData + 0x50F4, 0x0)
	local doNotChangeDirection = false
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local thespecial = IEex_ReadDword(eData + 0x48)
		if theopcode == 266 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if bit.band(thesavingthrow, 0x100000) == 0 then
				if theparameter2 == 0 then
					movementRate = movementRate + theparameter1
				elseif theparameter2 == 1 then
					movementRate = theparameter1
				elseif theparameter2 == 2 then
					movementRate = math.floor(movementRate * theparameter1 / 100)
				end
			end
		elseif theopcode == 500 and theresource == "MESPIN" and bit.band(thesavingthrow, 0x20000) == 0 or animationSequence == thespecial or (thespecial == 0 and animationSequence >= 11 and animationSequence <= 13) then
			doNotChangeDirection = true
		end
	end)
	if parameter2 == 0 then
		movementRate = movementRate + parameter1
	elseif parameter2 == 1 then
		movementRate = parameter1
	elseif parameter2 == 2 then
		movementRate = math.floor(movementRate * parameter1 / 100)
	end
	local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
	if bit.band(stateValue, 0x8000) > 0 then
		movementRate = movementRate * 2
	end
	if bit.band(stateValue, 0x10000) > 0 then
		movementRate = math.floor(movementRate / 2)
	end
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
	local disableTeleport = false
	local areaData = IEex_ReadDword(creatureData + 0x12)
	local areaRES = ""
	local areaX = 32767
	local areaY = 32767
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	local disableFlight = false
	if areaData > 0 then
		areaRES = IEex_ReadLString(areaData, 8)
		areaX = IEex_ReadDword(areaData + 0x54C)
		areaY = IEex_ReadDword(areaData + 0x550)
		local areaType = IEex_ReadWord(areaData + 0x40, 0x0)
		if bit.band(areaType, 0x800) > 0 then
			disableTeleport = true
			disableFlight = true
		elseif not IEex_GetActorSpellState(sourceID, 182) and not IEex_GetActorSpellState(sourceID, 189) then
			if bit.band(areaType, 0x1) > 0 then
--				IEex_WriteDword(creatureData + 0x740, bit.bor(extraFlags, 0x800))
--				IEex_ModifyTerrainTable(creatureData + 0x50BB, ex_outdoor_flight_terrain_table)
			else
				disableFlight = true
				disableTeleport = true
--				IEex_WriteDword(creatureData + 0x740, bit.bor(extraFlags, 0x800))
--				IEex_ModifyTerrainTable(creatureData + 0x50BB, ex_indoor_flight_terrain_table)
			end

		end
	end
	if (areaRES ~= "" and ex_ghostwalk_area["" .. sourceID] ~= areaRES) or animationSequence == 2 or animationSequence == 3 then
		ex_ghostwalk_dest["" .. sourceID] = {0, 0}
	end
	if areaRES ~= "" then
		ex_ghostwalk_area["" .. sourceID] = areaRES
	end
	local storedX = 0
	local storedY = 0
	if ex_ghostwalk_dest["" .. sourceID] ~= nil then		
		storedX = ex_ghostwalk_dest["" .. sourceID][1]
		storedY = ex_ghostwalk_dest["" .. sourceID][2]
	end
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	local special = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local action = IEex_ReadWord(creatureData + 0x476, 0x0)
	local actionRange = 1
	local pixelRange = 54
	local moveType = 3
	if action == 29 or action == 184 or action == 250 then
		moveType = 1
	end
	local isTouchSpell = false
	local withinRange = false
	if ((IEex_IsSprite(targetID, true) and (action == 31 or action == 113 or action == 191)) or action == 95 or action == 114 or action == 192) then
--		if IEex_ReadSignedWord(creatureData + 0x54E8, 0x0) > 0 then
			local resWrapper = IEex_DemandRes(IEex_GetActorSpellRES(sourceID), "SPL")
			if resWrapper:isValid() then
				local spellData = resWrapper:getData()
				actionRange = IEex_ReadWord(spellData + 0x90, 0x0)
				if actionRange == 0 or actionRange == 1 then
					isTouchSpell = true
				end
			end
			resWrapper:free()
			if actionRange > 28 then
				actionRange = 28
			end
			pixelRange = 16 * actionRange + 38
			if ((destinationX - targetX) / 16) ^ 2 + ((destinationY - targetY) / 12) ^ 2 <= (actionRange + 2) ^ 2 then
				withinRange = true
			end
			if actionRange >= 6 and ((destinationX - targetX) / 16) ^ 2 + ((destinationY - targetY) / 12) ^ 2 <= actionRange ^ 2 then
				withinRange = true
				destinationX = targetX
				destinationY = targetY
			elseif targetID ~= sourceID and IEex_GetDistance(destinationX, destinationY, storedX, storedY) < 20 then
				destinationX = 0
				destinationY = 0
			end
--		end
	elseif (IEex_IsSprite(targetID, true) and targetID ~= sourceID) or (action == 3 or action == 98 or action == 105 or action == 134) then
--[[
		if IEex_IsSprite(targetID, true) then
			destinationX = IEex_ReadDword(IEex_GetActorShare(targetID) + 0x6)
			destinationY = IEex_ReadDword(IEex_GetActorShare(targetID) + 0xA)
		end
--]]
		if (action == 3 or action == 98 or action == 105 or action == 134) then
			local equippedWeaponSlot = IEex_ReadByte(creatureData + 0x4BA4, 0x0)
			local equippedWeaponHeader = IEex_ReadByte(creatureData + 0x4BA6, 0x0)
			if equippedWeaponSlot < 11 or equippedWeaponSlot > 14 then
				if IEex_ReadDword(creatureData + 0x4AD8 + equippedWeaponSlot * 0x4) > 0 then
					local resWrapper = IEex_DemandRes(IEex_ReadLString(IEex_ReadDword(creatureData + 0x4AD8 + equippedWeaponSlot * 0x4) + 0xC, 8), "ITM")
					if resWrapper:isValid() then
						local itemData = resWrapper:getData()
						actionRange = IEex_ReadWord(itemData + 0x90 + equippedWeaponHeader * 0x38, 0x0)
					end
					resWrapper:free()
				end
			else
				IEex_IterateActorEffects(sourceID, function(eData)
					local theopcode = IEex_ReadDword(eData + 0x10)
					local theparameter2 = IEex_ReadDword(eData + 0x20)
					local thespecial = IEex_ReadDword(eData + 0x48)
					if theopcode == 288 and theparameter2 == 241 and thespecial == 7 then
						local theresource = IEex_ReadLString(eData + 0x94, 8)
						local resWrapper = IEex_DemandRes(theresource, "ITM")
						if resWrapper:isValid() then
							local itemData = resWrapper:getData()
							actionRange = IEex_ReadWord(itemData + 0x90, 0x0)
						end
						resWrapper:free()
					end
				end)
			end
		end
		if actionRange > 28 then
			actionRange = 28
		end
		pixelRange = 16 * actionRange + 38
		if ((destinationX - targetX) / 16) ^ 2 + ((destinationY - targetY) / 12) ^ 2 <= (actionRange + 2) ^ 2 then
			withinRange = true
		end
		if actionRange >= 6 and ((destinationX - targetX) / 16) ^ 2 + ((destinationY - targetY) / 12) ^ 2 <= actionRange ^ 2 and IEex_CheckActorLOSObject(sourceID, targetID) then
			withinRange = true
			destinationX = targetX
			destinationY = targetY
		end
	end
	if destinationX <= 0 or destinationY <= 0 then
		if storedX > 0 and storedY > 0 then
			destinationX = storedX
			destinationY = storedY
		else
			destinationX = targetX
			destinationY = targetY
		end
	end
	if not IEex_IsSprite(targetID, true) and (action == 3 or actionID == 94 or action == 105 or action == 134) then
		destinationX = targetX
		destinationY = targetY
	end
	if destinationX > 0 and destinationY > 0 then
		ex_ghostwalk_dest["" .. sourceID] = {destinationX, destinationY}
	end
	local targetShare = IEex_GetActorShare(targetID)
	if IEex_IsSprite(targetID, true) and targetID ~= sourceID and actionRange < 10 then
		local distanceMultiplier = 1
--[[
		local sourceAnimationData = IEex_ReadDword(creatureData + 0x50F0)
		local targetAnimationData = IEex_ReadDword(targetShare + 0x50F0)
		local sourcePersonalSpace = IEex_ReadByte(sourceAnimationData + 0x3E4, 0x0)
		local targetPersonalSpace = IEex_ReadByte(targetAnimationData + 0x3E4, 0x0)
		if IEex_ReadDword(targetShare + 0x4BE) == sourceID and sourcePersonalSpace ~= 0 and targetPersonalSpace ~= 0 then
			IEex_WriteByte(sourceAnimationData + 0x3E4, 1)
			IEex_WriteByte(targetAnimationData + 0x3E4, 1)
		end
--]]
--		if sourceAnimationData > 0 and targetAnimationData > 0 then
--			distanceMultiplier = (IEex_ReadDword(sourceAnimationData + 0x10) + IEex_ReadDword(targetAnimationData + 0x10)) / 24
			if not isTouchSpell then
				distanceMultiplier = (actionRange * 16 + 38) / 30
			else
				distanceMultiplier = .1
			end
--		end
		local offsetX = 0
		local offsetY = 0

		if destinationX < targetX then
			offsetX = -20
		elseif destinationX > targetX then
			offsetX = 20
		end
		if destinationY < targetY then
			offsetY = -20
		elseif destinationY > targetY then
			offsetY = 20
		end

		local offsetString = offsetX .. "." .. offsetY
		if ex_ghostwalk_offsets_taken["" .. targetID] == nil then
			ex_ghostwalk_offsets_taken["" .. targetID] = {}
		end
		if ex_current_ghostwalk_target_offset["" .. sourceID] ~= nil then
			if ex_current_ghostwalk_target_offset["" .. sourceID][1] ~= targetID then
				ex_ghostwalk_offsets_taken["" .. ex_current_ghostwalk_target_offset["" .. sourceID][1]][ex_current_ghostwalk_target_offset["" .. sourceID][2] .. "." .. ex_current_ghostwalk_target_offset["" .. sourceID][3]] = nil
				ex_current_ghostwalk_target_offset["" .. sourceID] = nil
			else
				offsetX = ex_current_ghostwalk_target_offset["" .. sourceID][2]
				offsetY = ex_current_ghostwalk_target_offset["" .. sourceID][3]
				if math.abs(offsetX) == 30 or math.abs(offsetY) == 30 then
					local emptySlotFound = false
					local otherOffsetString = "0.0"
					for key,value in pairs(ex_ghostwalk_offsets) do
						if not emptySlotFound then
							otherOffsetString = value[1] .. "." .. value[2]
							if ex_ghostwalk_offsets_taken["" .. targetID][otherOffsetString] == nil and math.abs(value[1]) ~= 30 and math.abs(value[2]) ~= 30 then
								emptySlotFound = true
								offsetX = value[1]
								offsetY = value[2]
								offsetString = otherOffsetString
								ex_ghostwalk_offsets_taken["" .. targetID][offsetString] = true
								ex_current_ghostwalk_target_offset["" .. sourceID] = {targetID, offsetX, offsetY}
							end
						end
					end
				end
				offsetString = offsetX .. "." .. offsetY
			end
		end
		if ex_current_ghostwalk_target_offset["" .. sourceID] == nil then
			if ex_ghostwalk_offsets_taken["" .. targetID][offsetString] == nil and offsetString ~= "0.0" then
				ex_ghostwalk_offsets_taken["" .. targetID][offsetString] = true
				ex_current_ghostwalk_target_offset["" .. sourceID] = {targetID, offsetX, offsetY}
			else
				local emptySlotFound = false
				local otherOffsetString = "0.0"
				for key,value in pairs(ex_ghostwalk_offsets) do
					if not emptySlotFound then
						otherOffsetString = value[1] .. "." .. value[2]
						if ex_ghostwalk_offsets_taken["" .. targetID][otherOffsetString] == nil then
							emptySlotFound = true
							offsetX = value[1]
							offsetY = value[2]
							offsetString = otherOffsetString
							ex_ghostwalk_offsets_taken["" .. targetID][offsetString] = true
							ex_current_ghostwalk_target_offset["" .. sourceID] = {targetID, offsetX, offsetY}
						end
					end
				end
			end
		end
		if (actionRange >= 6 or IEex_ReadDword(targetShare + 0x4BE) == sourceID) and math.abs(destinationX - targetX) <= pixelRange and math.abs(destinationY - targetY) <= pixelRange and IEex_CheckActorLOSObject(sourceID, targetID) then
--		if (actionRange >= 6 or IEex_ReadDword(targetShare + 0x4BE) == sourceID) and ((destinationX - targetX) / 16) ^ 2 + ((destinationY - targetY) / 12) ^ 2 <= (actionRange + 2) ^ 2 and IEex_CheckActorLOSObject(sourceID, targetID) then
			destinationX = targetX
			destinationY = targetY
		else
			destinationX = destinationX + math.floor(offsetX * distanceMultiplier)
			destinationY = destinationY + math.floor(offsetY * distanceMultiplier)
		end
	end
	local distX = destinationX - targetX
	local distY = destinationY - targetY
	local dist = math.floor((distX ^ 2 + distY ^ 2) ^ .5)
	local deltaX = 0
	local deltaY = 0
	if dist ~= 0 then
		deltaX = math.floor(movementRate * distX / dist)
		deltaY = math.floor(movementRate * distY / dist)
	end
	if math.abs(deltaX) > math.abs(distX) then
		deltaX = distX
	end
	if math.abs(deltaY) > math.abs(distY) then
		deltaY = distY
	end
	if (disableTeleport or disableFlight) and IEex_GetActorStat(sourceID, 75) > 0 then
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theopcode == 184 and theparent_resource == parent_resource then
				IEex_WriteDword(eData + 0x20, 0)
				IEex_WriteByte(creatureData + 0x9DC, 0)
			end
		end)
	elseif not disableTeleport and not disableFlight and IEex_GetActorStat(sourceID, 75) == 0 then
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theopcode == 184 and theparent_resource == parent_resource then
				IEex_WriteDword(eData + 0x20, 1)
				IEex_WriteByte(creatureData + 0x9DC, 1)
			end
		end)
	end
	if ((actionID ~= 31 and actionID ~= 95) or not withinRange) and not disableTeleport and not doNotChangeDirection then
		if IEex_IsSprite(targetID, true) and targetID ~= sourceID then
			local targetShare = IEex_GetActorShare(targetID)
			local newDirection = IEex_GetActorRequiredDirection(sourceID, IEex_ReadDword(targetShare + 0x6), IEex_ReadDword(targetShare + 0xA))
			ex_ghostwalk_direction[sourceID] = newDirection
			IEex_WriteWord(creatureData + 0x537C, 0)
			IEex_WriteByte(creatureData + 0x537E, (newDirection + 1) % 16)
			IEex_WriteByte(creatureData + 0x5380, newDirection)
		elseif math.abs(destinationX - targetX) > 50 or math.abs(destinationY - targetY) > 50 then
			local newDirection = IEex_GetActorRequiredDirection(sourceID, destinationX, destinationY)
			ex_ghostwalk_direction[sourceID] = newDirection
			IEex_WriteWord(creatureData + 0x537C, 0)
			IEex_WriteByte(creatureData + 0x537E, (newDirection + 1) % 16)
			IEex_WriteByte(creatureData + 0x5380, newDirection)
		elseif ex_ghostwalk_direction[sourceID] ~= nil then
			local newDirection = ex_ghostwalk_direction[sourceID]
			IEex_WriteWord(creatureData + 0x537C, 0)
			IEex_WriteByte(creatureData + 0x537E, (newDirection + 1) % 16)
			IEex_WriteByte(creatureData + 0x5380, newDirection)
		end
	end

	local finalX = targetX + deltaX
	local finalY = targetY + deltaY
	if IEex_IsGamePaused() then
		finalX = targetX
		finalY = targetY
	elseif movementRate >= dist then
		finalX = destinationX
		finalY = destinationY
	end
	if finalX < 0 then
		finalX = 1
	elseif finalX >= areaX then
		finalX = areaX - 1
	end
	if finalY < 0 then
		finalY = 1
	elseif finalY >= areaY then
		finalY = areaY - 1
	end
--	if ((actionID == 95 or actionID == 97 or actionID == 192) and IEex_CheckActorLOS(sourceID, actionX, actionY)) or actionID == 114 or actionID == 34 then return end
	if ex_specific_teleport_zone[areaRES] ~= nil then
		local noTeleportMapWrapper = IEex_DemandRes(areaRES .. "NT", "BMP")
		if noTeleportMapWrapper:isValid() then
			local noTeleportMapData = noTeleportMapWrapper:getData()
			local currentZone = IEex_GetBitmapPixelIndex(noTeleportMapData, math.floor(targetX / 16), math.floor(targetY / 12))
			local destinationZone = IEex_GetBitmapPixelIndex(noTeleportMapData, math.floor(finalX / 16), math.floor(finalY / 12))
			if currentZone ~= destinationZone then
				disableTeleport = true
			end
		end
		noTeleportMapWrapper:free()
	end
	if not disableTeleport then
		IEex_WriteByte(IEex_ReadDword(creatureData + 0x50F0) + 0x7, 0)
		if finalX ~= targetX or finalY ~= targetY or withinRange then
			ex_previous_ghostwalk_tick[sourceID] = IEex_GetGameTick()
		end
		if destinationX > 0 and destinationY > 0 then
			IEex_JumpActorToPoint(sourceID, finalX, finalY, true)
		end
	end
end

function IEex_RemoveEffectsByResource(actorID, resource_to_remove)
	if not IEex_IsSprite(actorID, false) then return end
	IEex_IterateActorEffects(actorID, function(eData)
		local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
		if theparent_resource == resource_to_remove then
			IEex_WriteDword(eData + 0x114, 1)
		end
	end)
end

function MEREMEFF(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	if spellRES == "" then
		spellRES = IEex_ReadLString(effectData + 0x90, 8)
	end
	IEex_RemoveEffectsByResource(targetID, spellRES)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["source_id"] = IEex_ReadDword(effectData + 0x10C)
})
end

ex_flying_animation = {[0xC000] = true, [0xC500] = true, [0x7F02] = true, [0xD300] = true, [0xD000] = true, [0xD400] = true, [0xD200] = true, [0x7F05] = true, [0x6405] = true, [0x7320] = true, [0x7321] = true, [0xE269] = true, [0xE289] = true, [0xE928] = true, [0x7F03] = true, [0xE908] = true, [0xE918] = true, [0xE249] = true, [0xE3BB] = true, [0xEF91] = true, [0xA000] = true, [0x1001] = true, [0xEA20] = true, }
ex_can_fly_animation = {[0xC000] = true, [0xC500] = true, [0x7F02] = true, [0xD300] = true, [0xD000] = true, [0xD400] = true, [0xD200] = true, [0x7F05] = true, [0x6405] = true, [0x7320] = true, [0x7321] = true, [0xE269] = true, [0xE289] = true, [0xE928] = true, [0x7F03] = true, [0xE908] = true, [0xE918] = true, [0xE249] = true, [0xE3BB] = true, [0xEF91] = true, [0xA000] = true, [0x1001] = true, [0xEA20] = true, [0xE7C9] = true, [0xEC33] = true, [0xED09] = true, [0x7F06] = true, [0x1201] = true, [0xEC0B] = true, [0xEC2B] = true, [0xEC4B] = true, [0xEC5B] = true, [0xEF0D] = true, [0xEF1D] = true, [0xEBCD] = true, }
function IEex_IsFlying(actorID)
	if not IEex_IsSprite(actorID, false) then return false end
	local creatureData = IEex_GetActorShare(actorID)
	local animation = IEex_ReadDword(creatureData + 0x5C4)
	local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
	return (((ex_flying_animation[animation] ~= nil or IEex_GetActorSpellState(actorID, 184)) and bit.band(stateValue, 0xFE9) == 0) or IEex_GetActorSpellState(actorID, 181) or IEex_GetActorSpellState(actorID, 182) or IEex_GetActorSpellState(actorID, 189))
end

function IEex_IsIncorporeal(actorID)
	if not IEex_IsSprite(actorID, false) then return false end
	return (IEex_GetActorSpellState(actorID, 182) or IEex_GetActorSpellState(actorID, 189))
end

function IEex_CanFly(actorID)
	if not IEex_IsSprite(actorID, false) then return false end
	local creatureData = IEex_GetActorShare(actorID)
	local animation = IEex_ReadDword(creatureData + 0x5C4)
	local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
	return (((ex_can_fly_animation[animation] ~= nil or IEex_GetActorSpellState(actorID, 184)) and bit.band(stateValue, 0xFE9) == 0) or IEex_GetActorSpellState(actorID, 181) or IEex_GetActorSpellState(actorID, 182) or IEex_GetActorSpellState(actorID, 189))
end

function MEHGTSET(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local currentHeight = IEex_ReadDword(creatureData + 0xE)
	if parameter2 == 0 then
		IEex_WriteDword(creatureData + 0xE, currentHeight - parameter1)
	elseif parameter2 == 1 then
		IEex_WriteDword(creatureData + 0xE, currentHeight * parameter1)
	elseif parameter2 == 2 then
		IEex_WriteDword(creatureData + 0xE, math.floor(currentHeight + (currentHeight * parameter1 / 100)))
	end
end

function MEHGTST(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local animation = IEex_ReadDword(creatureData + 0x5C4)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local special = IEex_ReadDword(effectData + 0x44)
	if special == 0 then
		local height = IEex_ReadSignedWord(creatureData + 0x720, 0x0)
--		IEex_DisplayString(height)
		if parameter2 == 0 then
			IEex_WriteWord(creatureData + 0x720, height + parameter1)
		elseif parameter2 == 1 then
			IEex_WriteWord(creatureData + 0x720, parameter1)
		elseif parameter2 == 2 then
			IEex_WriteWord(creatureData + 0x720, math.floor(height * (parameter1 / 100)))
		end
	elseif special == 1 then
		local speed = IEex_ReadSignedWord(creatureData + 0x722, 0x0)
--		IEex_DisplayString(speed)
		if parameter2 == 0 then
			IEex_WriteWord(creatureData + 0x722, speed + parameter1)
		elseif parameter2 == 1 then
			IEex_WriteWord(creatureData + 0x722, parameter1)
		elseif parameter2 == 2 then
			IEex_WriteWord(creatureData + 0x722, math.floor(speed * (parameter1 / 100)))
		end
	elseif special == 2 then
		local accel = IEex_ReadSignedWord(creatureData + 0x724, 0x0)
--		IEex_DisplayString(accel)
		if parameter2 == 0 then
			IEex_WriteWord(creatureData + 0x724, accel + parameter1)
		elseif parameter2 == 1 then
			IEex_WriteWord(creatureData + 0x724, parameter1)
		elseif parameter2 == 2 then
			IEex_WriteWord(creatureData + 0x724, math.floor(accel * (parameter1 / 100)))
		end
	elseif special == 3 then
		local minHeight = IEex_ReadSignedWord(creatureData + 0x726, 0x0)
--		IEex_DisplayString(minHeight)
		if parameter2 == 0 then
			IEex_WriteWord(creatureData + 0x726, minHeight + parameter1)
		elseif parameter2 == 1 then
			IEex_WriteWord(creatureData + 0x726, parameter1)
		elseif parameter2 == 2 then
			IEex_WriteWord(creatureData + 0x726, math.floor(minHeight * (parameter1 / 100)))
		end
	elseif special == 4 then
		local maxHeight = IEex_ReadSignedWord(creatureData + 0x728, 0x0)
--		IEex_DisplayString(maxHeight)
		if parameter2 == 0 then
			IEex_WriteWord(creatureData + 0x728, maxHeight + parameter1)
		elseif parameter2 == 1 then
			IEex_WriteWord(creatureData + 0x728, parameter1)
		elseif parameter2 == 2 then
			IEex_WriteWord(creatureData + 0x728, math.floor(maxHeight * (parameter1 / 100)))
		end
	end
end

function MEJUMPST(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local animation = IEex_ReadDword(creatureData + 0x5C4)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local special = IEex_ReadDword(effectData + 0x44)
	local sourceX, sourceY = IEex_GetActorLocation(targetID)
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	local speedIncrease = math.floor((IEex_GetDistance(sourceX, sourceY, targetX, targetY) * special / 2) / parameter1) - special
	if speedIncrease < 1 then
		speedIncrease = 1
	end
	local speed = IEex_ReadSignedWord(creatureData + 0x722, 0x0)
	if parameter2 == 0 then
		IEex_WriteWord(creatureData + 0x722, speed + speedIncrease)
	elseif parameter2 == 1 then
		IEex_WriteWord(creatureData + 0x722, speedIncrease)
	elseif parameter2 == 2 then
		IEex_WriteWord(creatureData + 0x722, math.floor(speed * (speedIncrease / 100)))
	end
end

function MEUNSTUC(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--[[
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
		if theopcode == 184 and theparent_resource == parent_resource then
			IEex_WriteDword(eData + 0x20, 0)
			IEex_WriteByte(creatureData + 0x9DC, 0)
		end
	end)
	IEex_WriteByte(creatureData + 0x9DC, 0)
--]]
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["parent_resource"] = "USUNSTUC",
["source_id"] = targetID
})
end

function MEANSUPP(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local visualHeight = IEex_ReadDword(creatureData + 0xE)
	local animationAlreadySuppressed = (IEex_ReadDword(effectData + 0x60) == 1)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	if visualHeight ~= 0 then
		IEex_WriteDword(creatureData + 0xA2C, 0)
		if not animationAlreadySuppressed then
			IEex_WriteDword(effectData + 0x60, 1)
			IEex_IterateActorEffects(targetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
				if theopcode == 413 and theparent_resource == parent_resource then
					local thevisualeffect = IEex_ReadDword(eData + 0x20)
					IEex_WriteDword(eData + 0x10, 0)
					IEex_WriteDword(eData + 0x1C, 0)
					IEex_WriteDword(eData + 0x20, 0)
					IEex_WriteDword(eData + 0x40, 0x400000)
					IEex_WriteDword(eData + 0x64, thevisualeffect)
				end
			end)
		end
	else
		if animationAlreadySuppressed then
			IEex_WriteDword(effectData + 0x60, 0)
			IEex_IterateActorEffects(targetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
				if theopcode == 0 and bit.band(thesavingthrow, 0x400000) > 0 and theparent_resource == parent_resource then
					local thevisualeffect = IEex_ReadDword(eData + 0x64)
					IEex_WriteDword(eData + 0x10, 413)
					IEex_WriteDword(eData + 0x20, thevisualeffect)
					IEex_WriteDword(eData + 0x40, 0)
					IEex_WriteDword(eData + 0x64, 0)
					IEex_WriteDword(creatureData + 0xA2C, bit.bor(IEex_ReadDword(creatureData + 0xA2C), 2 ^ thevisualeffect))
				end
			end)
		end
	end
end

function MEANSUP2(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local animationsToSuppress = bit.band(IEex_ReadDword(effectData + 0x44), 0xFFFFFFFF)
	local animations = IEex_ReadDword(creatureData + 0xA2C)
	IEex_WriteDword(creatureData + 0xA2C, bit.band(animations, 0xFFFFFFFF - animationsToSuppress))
	return true
end

function MESANCTI(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local hasSanctuary = false
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
		if theopcode == 20 and theparent_resource == parent_resource then
			hasSanctuary = true
		end
	end)
	if hasSanctuary then
		local animations = IEex_ReadDword(creatureData + 0xA2C)
		animations = bit.bor(animations, 0x1)
		animations = bit.band(animations, 0xFDFFFFFF)
		IEex_WriteDword(creatureData + 0xA2C, animations)
	else
		IEex_WriteDword(effectData + 0x110, 1)
--[[
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 0,
["resource"] = parent_resource,
["source_id"] = targetID
})
--]]
	end
end

ex_no_teleport_animations = {[61347] = true, [61363] = true, [61379] = true, [61395] = true, [61411] = true, [61427] = true, }

ex_ceiling_height = {["AR1000"] = 32767, ["AR1001"] = 140, ["AR1002"] = 140, ["AR1003"] = 55, ["AR1004"] = 75, ["AR1005"] = 65, ["AR1006"] = 75, ["AR1007"] = 110, ["AR1100"] = 32767, ["AR1101"] = 85, ["AR1102"] = 75, ["AR1103"] = 60, ["AR1104"] = 70, ["AR1105"] = 0, ["AR1106"] = 70, ["AR1107"] = 70, ["AR1200"] = 32767, ["AR1201"] = 75, ["AR2000"] = 32767, ["AR2001"] = 32767, ["AR2002"] = 180, ["AR2100"] = 32767, ["AR2101"] = 32767, ["AR2102"] = 32767, ["AR3000"] = 32767, ["AR3001"] = 160, ["AR3002"] = 170, ["AR3100"] = 32767, ["AR3101"] = 80, ["AR4000"] = 32767, ["AR4001"] = 70, ["AR4100"] = 32767, ["AR4101"] = 90, ["AR4102"] = 90, ["AR4103"] = 90, ["AR5000"] = 32767, ["AR5001"] = 32767, ["AR5002"] = 80, ["AR5004"] = 32767, ["AR5005"] = 32767, ["AR5010"] = 32767, ["AR5011"] = 32767, ["AR5012"] = 32767, ["AR5013"] = 32767, ["AR5014"] = 32767, ["AR5015"] = 32767, ["AR5016"] = 32767, ["AR5017"] = 32767, ["AR5018"] = 32767, ["AR5019"] = 32767, ["AR5020"] = 32767, ["AR5021"] = 32767, ["AR5022"] = 32767, ["AR5023"] = 32767, ["AR5024"] = 32767, ["AR5025"] = 32767, ["AR5026"] = 32767, ["AR5027"] = 32767, ["AR5028"] = 32767, ["AR5029"] = 32767, ["AR5030"] = 32767, ["AR5100"] = 200, ["AR5101"] = 170, ["AR5102"] = 110, ["AR5200"] = 32767, ["AR5201"] = 120, ["AR5202"] = 110, ["AR5203"] = 300, ["AR5300"] = 200, ["AR5301"] = 160, ["AR5302"] = 80, ["AR5303"] = 32767, ["AR6000"] = 32767, ["AR6001"] = 32767, ["AR6002"] = 32767, ["AR6003"] = 160, ["AR6004"] = 75, ["AR6005"] = 130, ["AR6006"] = 110, ["AR6007"] = 70, ["AR6008"] = 320, ["AR6009"] = 250, ["AR6010"] = 110, ["AR6050"] = 32767, ["AR6051"] = 150, ["AR6100"] = 32767, ["AR6101"] = 190, ["AR6102"] = 170, ["AR6103"] = 140, ["AR6104"] = 220, ["AR6200"] = 32767, ["AR6201"] = 32767, ["AR6300"] = 32767, ["AR6301"] = 310, ["AR6302"] = 320, ["AR6303"] = 170, ["AR6304"] = 200, ["AR6305"] = 170, ["AR6400"] = 32767, ["AR6401"] = 100, ["AR6402"] = 270, ["AR6403"] = 140, ["AR6500"] = 250, ["AR6501"] = 320, ["AR6502"] = 120, ["AR6503"] = 100, ["AR6600"] = 200, ["AR6601"] = 160, ["AR6602"] = 110, ["AR6603"] = 215, ["AR6700"] = 95, ["AR6701"] = 110, ["AR6702"] = 230, ["AR6703"] = 32767, ["AR6800"] = 32767, }
ex_specific_floor_height = {["AR3000"] = {[0xFF00] = -750}, ["AR5200"] = {[0xFF00] = -360}, ["AR5300"] = {[0xFF00] = -1500}, ["AR5303"] = {[0xFF00] = -4000}, ["AR6000"] = {[0xFF00] = -900}, ["AR6001"] = {[0xFF00] = -4800}, ["AR6051"] = {[0xFF00] = -300}, ["AR6104"] = {[0xFF00] = -20}, ["AR6300"] = {[0xFF00] = -120}, ["AR6302"] = {[0xFF00] = -900}, ["AR6303"] = {[0xFF00] = -900}, ["AR6304"] = {[0xFF00] = -900}, ["AR6305"] = {[0xFF00] = -900}, ["AR6400"] = {[0xFF00] = -3500}, ["AR6703"] = {[0xFF00] = -5800}, ["AR6800"] = {[0xFF00] = -5000}, }
ex_specific_floor_height_door = {["AR6051"] = {[0xFFFF00] = {-300, 0, "BRIDGE1"}}, }
ex_specific_floor_spell = {["AR6051"] = {[0xFF00] = "USFL6051"}, ["AR6104"] = {[0xFF00] = "USFL6104"}, ["AR6300"] = {[0xFF00] = "USFL6300"}, }
ex_specific_floor_spell_door = {["AR6051"] = {[0xFFFF00] = {"USFL6051", "", "BRIDGE1"}}, }
ex_specific_teleport_zone = {["AR4102"] = true, ["AR4103"] = true, ["AR5202"] = true, ["AR6305"] = true, }
ex_record_translucency = {}
ex_burrowing_previous_emerge_time = {}
function MEHGTMOD(effectData, creatureData)
	if true then return end
end
function IEex_HeightMod(creatureData)
--	print(IEex_ReadDword(effectData + 0xC))
	if ex_no_teleport_animations[IEex_ReadDword(creatureData + 0x5C4)] then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = targetID
	local savingthrow = 0
	local parent_resource = ""
	local spellRES = ""
	local casterlvl = 1
	local internalFlags = 0
	local roofHeight = 32767
	local targetHeight = 70
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
	local disableTeleport = false
	local disableFlight = false
	local areaData = IEex_ReadDword(creatureData + 0x12)
	local areaRES = ""
	local areaType = 0
	local isFlying = IEex_IsFlying(targetID)
	local isIncorporeal = IEex_IsIncorporeal(targetID)
	local isBurrowing = IEex_GetActorSpellState(targetID, 218)
	local hasTeleportStep = false
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	local canFallIntoPits = (bit.band(extraFlags, 0x8000) > 0)
	local fallIntoPitFunctionDetected = false
	if areaData > 0 then
		areaRES = IEex_ReadLString(areaData, 8)
		areaType = IEex_ReadWord(areaData + 0x40, 0x0)
		if bit.band(areaType, 0x800) > 0 then
			disableTeleport = true
			disableFlight = true
		elseif bit.band(areaType, 0x1) == 0 and not isIncorporeal then
			disableTeleport = true
			disableFlight = true
		end
	end
	if ex_ceiling_height[areaRES] ~= nil then
		roofHeight = ex_ceiling_height[areaRES] * 2
	end
	local animation = IEex_ReadDword(creatureData + 0x5C4)
	local height = IEex_ReadSignedWord(creatureData + 0x720, 0x0)

	local speed = IEex_ReadSignedWord(creatureData + 0x722, 0x0)
	local accel = IEex_ReadSignedWord(creatureData + 0x724, 0x0)
	if height == -1 and speed == -1 and accel == -1 then
		height = 0
		speed = 0
		accel = -2
		IEex_WriteWord(creatureData + 0x720, height)
		IEex_WriteWord(creatureData + 0x722, speed)
		IEex_WriteWord(creatureData + 0x724, accel)
	end
	local extraSpeed = 0
	local extraAccel = 0
	local minHeight = 0
	local maxHeight = 0
	local minSpeed = 0
	local previousHeight = height
	local floorSpellRES = ""
	local targetX, targetY = IEex_GetActorLocation(targetID)
	if ex_specific_floor_height[areaRES] ~= nil and not IEex_IsFlying(targetID) then
		local resWrapper = IEex_DemandRes(areaRES .. "H2", "BMP")
		if resWrapper:isValid() then
			local bitmapData = resWrapper:getData()
			
			local specificFloorHeight = IEex_GetBitmapPixelColor(bitmapData, math.floor(targetX / 16), math.floor(targetY / 12))

			if ex_specific_floor_height[areaRES][specificFloorHeight] ~= nil and canFallIntoPits then
				minHeight = ex_specific_floor_height[areaRES][specificFloorHeight] * 2
			elseif ex_specific_floor_height_door[areaRES] ~= nil and ex_specific_floor_height_door[areaRES][specificFloorHeight] ~= nil then
				IEex_IterateDoors(targetID, function(share)
					if IEex_ReadLString(share + 0x598, 8) == ex_specific_floor_height_door[areaRES][specificFloorHeight][3] then
						if bit.band(IEex_ReadDword(share + 0x5C4), 0x1) > 0 then
							fallIntoPitFunctionDetected = true
							disableTeleport = false
							minHeight = ex_specific_floor_height_door[areaRES][specificFloorHeight][1] * 2
						else
							minHeight = ex_specific_floor_height_door[areaRES][specificFloorHeight][2] * 2
						end
					end
				end)
			end
			if ex_specific_floor_spell[areaRES] ~= nil and ex_specific_floor_spell[areaRES][specificFloorHeight] ~= nil and canFallIntoPits then
				floorSpellRES = ex_specific_floor_spell[areaRES][specificFloorHeight]
			elseif ex_specific_floor_spell_door[areaRES] ~= nil and ex_specific_floor_spell_door[areaRES][specificFloorHeight] ~= nil then
				IEex_IterateDoors(targetID, function(share)
					if IEex_ReadLString(share + 0x598, 8) == ex_specific_floor_height_door[areaRES][specificFloorHeight][3] then
						if bit.band(IEex_ReadDword(share + 0x5C4), 0x1) > 0 then
							floorSpellRES = ex_specific_floor_spell_door[areaRES][specificFloorHeight][1]
						else
							floorSpellRES = ex_specific_floor_spell_door[areaRES][specificFloorHeight][2]
						end
					end
				end)
			end
		end
		resWrapper:free()
	end
	local centerHeight = minHeight
	local doNotModifyHeight = false
	local acceptableBurrowingTerrain = {}
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		if theopcode == 288 and theparameter2 == 190 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if thespecial == 1 then
				extraSpeed = extraSpeed + theparameter1
			elseif thespecial == 2 then
				extraAccel = extraAccel + theparameter1
			elseif thespecial == 3 then
				minHeight = minHeight + theparameter1
			elseif thespecial == 4 then
				maxHeight = maxHeight + theparameter1
			elseif thespecial == 5 then
				centerHeight = centerHeight + theparameter1
			elseif thespecial == 6 then
				minSpeed = theparameter1
			elseif thespecial == 7 then
				extraSpeed = extraSpeed + theparameter1
			end
		elseif theopcode == 288 and theparameter2 == 218 then
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			for i = 0, 15, 1 do
				if bit.band(thesavingthrow, 2 ^ (i + 16)) ~= 0 then
					acceptableBurrowingTerrain[i] = true
				end
			end
			if bit.band(thesavingthrow, 0x8000) > 0 and IEex_ReadByte(creatureData + 0x24, 0x0) == 128 then
				isBurrowing = false
			end
		elseif theopcode == 500 and theresource == "MEHGTMOD" then
			spellRES = IEex_ReadLString(eData + 0x1C, 8)
			savingthrow = IEex_ReadDword(eData + 0x40)
			parent_resource = IEex_ReadLString(eData + 0x94, 8)
			casterlvl = IEex_ReadDword(eData + 0xC8)
			internalFlags = IEex_ReadDword(eData + 0xD8)
			if spellRES == "" and #parent_resource < 8 then
				spellRES = parent_resource .. "E"
			end
			if IEex_ReadDword(eData + 0x110) > 0 then
				sourceID = IEex_ReadDword(eData + 0x110)
			end
		elseif theopcode == 500 and theresource == "METELMOV" then
			hasTeleportStep = true
		elseif theopcode == 500 and (theresource == "MEGHOSTW" or theresource == "MEWINGBU") then
			fallIntoPitFunctionDetected = true
		elseif theopcode == 206 and theresource == "MEHGTMOD" then
			doNotModifyHeight = true
		end
	end)
	if doNotModifyHeight then return false end
	local isBurrowingOut = false
	if isBurrowing then
		local searchMapWrapper = IEex_DemandRes(areaRES .. "SR", "BMP")
		if searchMapWrapper:isValid() then
			local searchMapData = searchMapWrapper:getData()
			local currentZone = IEex_GetBitmapPixelIndex(searchMapData, math.floor(targetX / 16), math.floor(targetY / 12))
			if not acceptableBurrowingTerrain[currentZone] then
				ex_burrowing_previous_emerge_time[targetID] = IEex_GetGameTick()
--				isBurrowing = false
--				isBurrowingOut = true
			end
		end
		searchMapWrapper:free()
		local action = IEex_ReadWord(creatureData + 0x476, 0x0)
		local actionTargetID = IEex_ReadDword(creatureData + 0x4BE)
		if ((action == 31 or action == 191) and not IEex_GetActorSpellState(actionTargetID, 218)) or (action == 95 or action == 192) then
			ex_burrowing_previous_emerge_time[targetID] = IEex_GetGameTick()
--			isBurrowing = false
--			isBurrowingOut = true
		elseif action == 3 or action == 98 or action == 105 or action == 134 or action == 92 or action == 149 or action == 174 or action == 299 then
			local animationSequence = IEex_ReadByte(creatureData + 0x50F4, 0x0)
			if animationSequence == 0 or animationSequence == 8 or animationSequence == 11 or animationSequence == 12 or animationSequence == 13 then
				ex_burrowing_previous_emerge_time[targetID] = IEex_GetGameTick()
--				isBurrowing = false
--				isBurrowingOut = true
			end
--[[
			if IEex_ReadSignedByte(creatureData + 0x5622, 0x0) >= 0 then
				isBurrowing = false
				isBurrowingOut = true
			end
--]]
		end
		if ex_burrowing_previous_emerge_time[targetID] ~= nil and IEex_GetGameTick() - ex_burrowing_previous_emerge_time[targetID] < 30 then
			isBurrowing = false
			isBurrowingOut = true
		end
	end
	if isBurrowing then
		minHeight = -200
		centerHeight = -1000
		minSpeed = -1
		extraSpeed = -50
--		IEex_WriteDword(creatureData + 0x920, bit.bor(IEex_ReadDword(creatureData + 0x920), 0x10))
--		IEex_WriteByte(creatureData + 0x8A0, 0)
	elseif isBurrowingOut and height < 0 then
		minHeight = -200
		maxHeight = 50
		minSpeed = -1
		extraSpeed = 50
	end
	if isFlying then
		if isIncorporeal or IEex_GetActorSpellState(targetID, 181) then
			local isSelected = false
			for i, id in ipairs(IEex_GetAllActorIDSelected()) do
				if id == targetID then
					isSelected = true
				end
			end
			if IEex_IsKeyDown(160) and isSelected and height <= 500 then
				extraSpeed = extraSpeed + 5
				if accel == -1 or accel == -2 then
					accel = 0
				end
			end
			if IEex_IsKeyDown(161) and isSelected then
				extraSpeed = extraSpeed - 5
				if accel == -1 or accel == -2 then
					accel = 0
				end
			end
			if speed <= 0 and (accel == -1 or accel == -2) then
				speed = 0
				accel = 0
			end
		elseif IEex_GetActorSpellState(targetID, 184) and not disableFlight then
			local action = IEex_ReadWord(creatureData + 0x476, 0x0)
			local actionTargetID = IEex_ReadDword(creatureData + 0x4BE)
			local actionTargetShare = IEex_GetActorShare(actionTargetID)
			local actionTargetHeight = 0
			local destinationX = IEex_ReadDword(creatureData + 0x556E)
			local destinationY = IEex_ReadDword(creatureData + 0x5572)
			local movementRate = 9
			IEex_IterateActorEffects(sourceID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				if theopcode == 266 then
					local theparameter1 = IEex_ReadDword(eData + 0x1C)
					local theparameter2 = IEex_ReadDword(eData + 0x20)
					local thesavingthrow = IEex_ReadDword(eData + 0x40)
					if bit.band(thesavingthrow, 0x100000) == 0 then
						if theparameter2 == 0 then
							movementRate = movementRate + theparameter1
						elseif theparameter2 == 1 then
							movementRate = theparameter1
						elseif theparameter2 == 2 then
							movementRate = math.floor(movementRate * theparameter1 / 100)
						end
					end
				end
			end)
			local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
			if bit.band(stateValue, 0x8000) > 0 then
				movementRate = movementRate * 2
			end
			if bit.band(stateValue, 0x10000) > 0 then
				movementRate = math.floor(movementRate / 2)
			end
			local actionRange = 1
			if ((IEex_IsSprite(actionTargetID, true) and actionTargetID ~= targetID and (action == 31 or action == 113 or action == 191)) or action == 95 or action == 114 or action == 192) then
				if IEex_IsSprite(actionTargetID, true) then
					destinationX = IEex_ReadDword(actionTargetShare + 0x6)
					destinationY = IEex_ReadDword(actionTargetShare + 0xA)
					actionTargetHeight = IEex_ReadSignedWord(actionTargetShare + 0x720, 0x0)
				else
					destinationX = IEex_ReadDword(creatureData + 0x540)
					destinationY = IEex_ReadDword(creatureData + 0x544)
				end
				if IEex_ReadSignedWord(creatureData + 0x54E8, 0x0) > 0 then
					local resWrapper = IEex_DemandRes(IEex_GetActorSpellRES(sourceID), "SPL")
					if resWrapper:isValid() then
						local spellData = resWrapper:getData()
						actionRange = IEex_ReadWord(spellData + 0x90, 0x0)
					end
					resWrapper:free()
				end
				local targetDistance = IEex_GetDistance(targetX, targetY, destinationX, destinationY)
				if hasTeleportStep then
					if actionRange > 5 and height <= 215 then
						height = 200
					elseif ex_previous_ghostwalk_tick[targetID] == IEex_GetGameTick() then
						height = actionTargetHeight
					end
				else
					if actionRange <= 5 and targetDistance ~= 0 and movementRate ~= 0 and (ex_previous_ghostwalk_tick[targetID] == IEex_GetGameTick() or targetDistance < 60) then
						extraSpeed = extraSpeed + math.ceil((actionTargetHeight - height) / (targetDistance / movementRate))
					elseif actionRange > 5 and height <= 200 then
						extraSpeed = extraSpeed + 15
					end
				end
			elseif (IEex_IsSprite(actionTargetID, true) and actionTargetID ~= targetID) or (action == 3 or action == 98 or action == 105 or action == 134) then
				if IEex_IsSprite(actionTargetID, true) then
					destinationX = IEex_ReadDword(actionTargetShare + 0x6)
					destinationY = IEex_ReadDword(actionTargetShare + 0xA)
					actionTargetHeight = IEex_ReadSignedWord(actionTargetShare + 0x720, 0x0)
				end
				if (action == 3 or action == 98 or action == 105 or action == 134) then
					local equippedWeaponSlot = IEex_ReadByte(creatureData + 0x4BA4, 0x0)
					local equippedWeaponHeader = IEex_ReadByte(creatureData + 0x4BA6, 0x0)
					if equippedWeaponSlot < 11 or equippedWeaponSlot > 14 then
						if IEex_ReadDword(creatureData + 0x4AD8 + equippedWeaponSlot * 0x4) > 0 then
							local resWrapper = IEex_DemandRes(IEex_ReadLString(IEex_ReadDword(creatureData + 0x4AD8 + equippedWeaponSlot * 0x4) + 0xC, 8), "ITM")
							if resWrapper:isValid() then
								local itemData = resWrapper:getData()
								actionRange = IEex_ReadWord(itemData + 0x90 + equippedWeaponHeader * 0x38, 0x0)
							end
							resWrapper:free()
						end
					else
						IEex_IterateActorEffects(sourceID, function(eData)
							local theopcode = IEex_ReadDword(eData + 0x10)
							local theparameter2 = IEex_ReadDword(eData + 0x20)
							local thespecial = IEex_ReadDword(eData + 0x48)
							if theopcode == 288 and theparameter2 == 241 and thespecial == 7 then
								local theresource = IEex_ReadLString(eData + 0x94, 8)
								local resWrapper = IEex_DemandRes(theresource, "ITM")
								if resWrapper:isValid() then
									local itemData = resWrapper:getData()
									actionRange = IEex_ReadWord(itemData + 0x90, 0x0)
								end
								resWrapper:free()
							end
						end)
					end
				end
				local targetDistance = IEex_GetDistance(targetX, targetY, destinationX, destinationY)
				if hasTeleportStep then
					if actionRange > 5 and height <= 215 then
						height = 200
					elseif ex_previous_ghostwalk_tick[targetID] == IEex_GetGameTick() then
						height = actionTargetHeight
					end
				else
					if actionRange <= 5 and targetDistance ~= 0 and movementRate ~= 0 and (ex_previous_ghostwalk_tick[targetID] == IEex_GetGameTick() or targetDistance < 60) then
						extraSpeed = extraSpeed + math.ceil((actionTargetHeight - height) / (targetDistance / movementRate))
					elseif actionRange > 5 and height <= 200 then
						extraSpeed = extraSpeed + 15
					end
				end
			elseif height <= 200 then
				if hasTeleportStep then
					height = 200
				else
					extraSpeed = extraSpeed + 15
				end
			end
			if speed <= 0 and (accel == -1 or accel == -2) then
				speed = 0
				accel = 0
			end
		else
			if speed == 0 and accel == 0 then
				accel = -2
			end
		end
	end
	accel = accel + extraAccel
	if minSpeed == 0 then
		minSpeed = -32768
	end
	if height > minHeight and (height > 0 or minHeight >= 0) and not isBurrowingOut then
		IEex_WriteByte(creatureData + 0x9DC, 1)
		IEex_WriteByte(IEex_ReadDword(creatureData + 0x50F0) + 0x7, 0)
	end
	if height == 0 and speed + extraSpeed == 0 and accel <= 0 and minHeight == 0 and not IEex_GetActorSpellState(targetID, 184) and not IEex_GetActorSpellState(targetID, 190) and not fallIntoPitFunctionDetected then
		extraFlags = bit.band(extraFlags, 0xFFFF7FFF)
		IEex_WriteDword(creatureData + 0x740, extraFlags)
		return
	else
		extraFlags = bit.bor(extraFlags, 0x8000)
		IEex_WriteDword(creatureData + 0x740, extraFlags)
	end
	local timeSlowed, targetNotSlowed = IEex_CheckGlobalEffectOnActor(targetID, 0x2)
	if IEex_GetGameTick() % ex_time_slow_speed_divisor ~= 0 then
		if timeSlowed and not targetNotSlowed then
			IEex_WriteDword(creatureData + 0x5326, 0)
			return true
		end
	end
	if ((bit.band(areaType, 0x1) == 0 and not isIncorporeal and height == minHeight) or disableTeleport) and IEex_GetActorStat(targetID, 75) > 0 then
		IEex_WriteByte(creatureData + 0x9DC, 0)
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theopcode == 184 and theparent_resource == parent_resource then
				IEex_WriteDword(eData + 0x20, 0)
			end
		end)
	elseif (bit.band(areaType, 0x1) > 0 or isIncorporeal or height > minHeight) and not disableTeleport and IEex_GetActorStat(targetID, 75) == 0 then
		IEex_WriteByte(creatureData + 0x9DC, 1)
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theopcode == 184 and theparent_resource == parent_resource then
				IEex_WriteDword(eData + 0x20, 1)
			end
		end)
	end
--[[
	if minHeight < 0 then
		minHeight = 0
	end
--]]
	if maxHeight <= 0 or maxHeight > 10000 then
		maxHeight = 10000
	end
	if maxHeight > (roofHeight - targetHeight) and not isIncorporeal then
		if targetHeight >= roofHeight then
			maxHeight = 1
		else
			maxHeight = (roofHeight - targetHeight)
		end
	end
	if minHeight >= maxHeight then
		minHeight = maxHeight - 1
	end

	if height <= minHeight then
		height = minHeight
		if speed < 0 then
			speed = 0
		end
	elseif height >= maxHeight then
		height = maxHeight - 1
		if speed > 0 then
			if speed >= 33 and maxHeight < 10000 and not isIncorporeal and not IEex_GetActorSpellState(targetID, 218) then
				local damageDice = math.floor((speed - 30) / 3)
				if damageDice > 100 then
					damageDice = 100
				end
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter2"] = 210,
["parent_resource"] = "MEFALDM2",
["source_target"] = targetID,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = 0x600 + damageDice * 0x10000,
["savingthrow"] = 0x4090000,
["resource"] = "EXDAMAGE",
["parent_resource"] = "MEFALDM2",
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["resource"] = "MEFALDM2",
["source_target"] = targetID,
["source_id"] = sourceID
})
			end
			speed = 0
		end
	end
	height = height + speed + extraSpeed
	if height - speed < centerHeight then
		speed = speed - accel
	elseif height - speed > centerHeight then
		speed = speed + accel
	end
	if speed <= minSpeed then
		speed = minSpeed + 1
	end

	if height <= minHeight then
		height = minHeight
		
		if speed < 0 then
			if speed <= -33 and (minHeight <= 0 or bit.band(savingthrow, 0x10000) > 0) and not isIncorporeal and not IEex_GetActorSpellState(targetID, 218) then
				local damageDice = math.floor(math.abs(speed + 30) / 3)
				if damageDice > 100 then
					damageDice = 100
				end
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter2"] = 210,
["parent_resource"] = "MEFALDMG",
["source_target"] = targetID,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = 0x600 + damageDice * 0x10000,
["savingthrow"] = 0x4090000,
["resource"] = "EXDAMAGE",
["parent_resource"] = "MEFALDMG",
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["resource"] = "MEFALDMG",
["source_target"] = targetID,
["source_id"] = sourceID
})
				IEex_IterateActorEffects(targetID, function(eData)
					local theopcode = IEex_ReadDword(eData + 0x10)
					local theresource = IEex_ReadLString(eData + 0x30, 8)
					local thespecial = IEex_ReadDword(eData + 0x48)
					if theopcode == 500 and theresource == "MEWINGBU" and thespecial < 0 then
						IEex_WriteDword(eData + 0x1C, 0)
					end
				end)
			end
--			speed = 0
		end
	elseif height >= maxHeight then
		height = maxHeight - 1
		if speed > 0 then
			if speed >= 33 and maxHeight < 10000 and not isIncorporeal and not IEex_GetActorSpellState(targetID, 218) then
				local damageDice = math.floor((speed - 30) / 3)
				if damageDice > 100 then
					damageDice = 100
				end
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter2"] = 210,
["parent_resource"] = "MEFALDM2",
["source_target"] = targetID,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = 0x600 + damageDice * 0x10000,
["savingthrow"] = 0x4090000,
["resource"] = "EXDAMAGE",
["parent_resource"] = "MEFALDM2",
["internal_flags"] = internalFlags,
["source_target"] = targetID,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["resource"] = "MEFALDM2",
["source_target"] = targetID,
["source_id"] = sourceID
})
			end
			speed = 0
		end
	end
--	if bit.band(IEex_ReadDword(creatureData + 0x434), 0x2000) > 0 then return end

	IEex_WriteDword(creatureData + 0x5326, 0)
	if (minHeight <= 0 or bit.band(savingthrow, 0x10000) > 0) and bit.band(savingthrow, 0x20000) == 0 and (height <= minHeight and (speed < 0 or (speed <= 0 and minHeight >= 0 and not isFlying and not IEex_GetActorSpellState(targetID, 218))) and accel <= 0) then 
		IEex_WriteWord(creatureData + 0x722, 0)
		IEex_WriteWord(creatureData + 0x724, -2)
--[[
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theparent_resource == parent_resource and parent_resource ~= "" then
				if theopcode == 184 then
					IEex_WriteDword(eData + 0x20, 0)
					IEex_WriteByte(creatureData + 0x9DC, 0)
				end
				IEex_WriteDword(eData + 0x114, 1)
			end
		end)
--]]
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = parent_resource,
--["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = sourceID
})
--		IEex_WriteDword(creatureData + 0xE, 0)
		if bit.band(savingthrow, 0x80000) > 0 and spellRES ~= "" then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 9,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["internal_flags"] = internalFlags,
["source_x"] = IEex_ReadDword(creatureData + 0x6),
["source_y"] = IEex_ReadDword(creatureData + 0xA),
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["source_target"] = targetID,
["source_id"] = sourceID
})
		end
		if floorSpellRES ~= "" then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 9,
["resource"] = floorSpellRES,
["parent_resource"] = floorSpellRES,
["internal_flags"] = internalFlags,
["source_x"] = IEex_ReadDword(creatureData + 0x6),
["source_y"] = IEex_ReadDword(creatureData + 0xA),
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["source_target"] = targetID,
["source_id"] = sourceID
})
		end
		if minHeight <= 0 and IEex_IsSprite(targetID, false) then
--			height = 0
		end
		if not isIncorporeal and targetID ~= IEex_GetActorIDCharacter(0) and targetID ~= IEex_GetActorIDCharacter(1) and targetID ~= IEex_GetActorIDCharacter(2) and targetID ~= IEex_GetActorIDCharacter(3) and targetID ~= IEex_GetActorIDCharacter(4) and targetID ~= IEex_GetActorIDCharacter(5) then
			IEex_IterateActorEffects(targetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
				if theopcode == 184 and theparent_resource == parent_resource then
					IEex_WriteDword(eData + 0x20, 0)
					IEex_WriteByte(creatureData + 0x9DC, 0)
				end
			end)
			IEex_WriteByte(creatureData + 0x9DC, 0)
--			IEex_JumpActorToPoint(targetID, targetX, targetY, true)

			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 3,
["duration"] = 1,
["resource"] = "MEUNSTUC",
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = targetID
})

		end
	end
	if height ~= 0 then
		IEex_WriteDword(creatureData + 0xA2C, 0)
	end
	IEex_WriteWord(creatureData + 0x720, height)
	IEex_WriteWord(creatureData + 0x722, speed)
	local visualHeight = -math.ceil(height / 2)
	if visualHeight == -0 then
		visualHeight = 0
	end
	IEex_WriteDword(creatureData + 0xE, visualHeight)

	if height < -1 then
		local heightMap2Wrapper = IEex_DemandRes(areaRES .. "H2", "BMP")
		local visualCoverHeight = 0
		local visualCoverHeightColor = 0
		if heightMap2Wrapper:isValid() and ex_specific_floor_height[areaRES] ~= nil then
			local heightMap2Data = heightMap2Wrapper:getData()
			visualCoverHeightColor = IEex_GetBitmapPixelColor(heightMap2Data, math.floor(targetX / 16), math.floor((targetY + visualHeight) / 12))
			if ex_specific_floor_height[areaRES][visualCoverHeightColor] ~= nil then
				visualCoverHeight = ex_specific_floor_height[areaRES][visualCoverHeightColor] * 2
			end
		end
		if height < visualCoverHeight then
			if ex_record_translucency[targetID] == nil then
				ex_record_translucency[targetID] = IEex_ReadWord(creatureData + 0x9D2, 0x0)
			end
			if IEex_ReadWord(creatureData + 0x9D2, 0x0) < 180 then
				IEex_WriteWord(creatureData + 0x9D2, 180)
			end
		elseif ex_record_translucency[targetID] ~= nil then
			IEex_WriteWord(creatureData + 0x9D2, ex_record_translucency[targetID])
			ex_record_translucency[targetID] = nil
		end
		heightMap2Wrapper:free()
	end

	local extraFlags = IEex_ReadDword(creatureData + 0x740)
--[[
	local eyeHeight = height + targetHeight
	if eyeHeight < 0 then
		IEex_WriteDword(creatureData + 0x740, bit.bor(extraFlags, 0x800))
		IEex_ModifyTerrainTable(creatureData + 0x50BB, ex_pit_terrain_table)
	end
--]]
--[[
	if eyeHeight < minHeight then
		IEex_WriteDword(creatureData + 0x740, bit.bor(extraFlags, 0x800))
		IEex_ModifyTerrainTable(creatureData + 0x50CB, ex_no_vision_terrain_table)
	elseif eyeHeight < 0 then
		IEex_WriteDword(creatureData + 0x740, bit.bor(extraFlags, 0x800))
		IEex_ModifyTerrainTable(creatureData + 0x50CB, ex_underground_vision_terrain_table)
	end
--]]
	return true
end

ex_pit_terrain_table = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1, -1}
ex_outdoor_flight_terrain_table = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, 5}
ex_indoor_flight_terrain_table = {-1, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, 5, 5, -1, -1, 5}
ex_xray_vision_terrain_table = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}
ex_no_vision_terrain_table = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
ex_underground_vision_terrain_table = {-1, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1, -1, 5, -1, -1, 5}

ex_default_terrain_table_1 = {-1, 5, 5, 5, 5, 5, 5, 5, -1, 5, -1, 5, -1, -1, -1, 5}
ex_default_terrain_table_2 = {-1, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, 5, 5, -1, 5, 5}
ex_default_terrain_table_3 = {-1, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, 5, 5, -1, 5, 5}

function IEex_ModifyTerrainTable(offset, terraintable)
	for i = 1, 16, 1 do
		IEex_WriteByte(offset + i - 1, terraintable[i])
	end
end

function MESMDAOE(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if IEex_GetActorShare(sourceID) <= 0 then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local special = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local found_it = false
	IEex_IterateIDs(IEex_ReadDword(creatureData + 0x12), 0, function(id)
		local projectileData = IEex_GetActorShare(id)
		if found_it == false and (IEex_ReadWord(projectileData + 0x6E, 0x0) == special or special == -1) and IEex_ReadDword(projectileData + 0x72) == sourceID then
			found_it = true
			IEex_WriteWord(projectileData + 0x2AE, math.floor(IEex_ReadWord(projectileData + 0x2AE, 0x0) * parameter1 / 100))
		end
	end)
end

function MEACTIVA(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	if targetID <= 0 or not IEex_IsSprite(targetID, true) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	IEex_WriteByte(creatureData + 0x838, parameter1)
end

function MECIRCLE(effectData, creatureData)
--	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	if targetID <= 0 or not IEex_IsSprite(targetID, true) then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local animationData = IEex_ReadDword(creatureData + 0x50F0)
	if bit.band(savingthrow, 0x10000) == 0 then
		if parameter2 == 0 then
			IEex_WriteDword(animationData + 0x8, IEex_ReadDword(animationData + 0x8) - parameter1)
			IEex_WriteDword(animationData + 0xC, IEex_ReadDword(animationData + 0xC) - math.floor(parameter1 * 3 / 4))
			IEex_WriteDword(animationData + 0x10, IEex_ReadDword(animationData + 0x10) + parameter1)
			IEex_WriteDword(animationData + 0xC, IEex_ReadDword(animationData + 0x14) + math.floor(parameter1 * 3 / 4))
		elseif parameter2 == 1 then
			IEex_WriteDword(animationData + 0x8, 0 - parameter1)
			IEex_WriteDword(animationData + 0xC, 0 - math.floor(parameter1 * 3 / 4))
			IEex_WriteDword(animationData + 0x10, parameter1)
			IEex_WriteDword(animationData + 0xC, math.floor(parameter1 * 3 / 4))
		elseif parameter2 == 2 then
			IEex_WriteDword(animationData + 0x8, math.floor(IEex_ReadDword(animationData + 0x8) * parameter1 / 100))
			IEex_WriteDword(animationData + 0xC, math.floor(IEex_ReadDword(animationData + 0xC) * parameter1 / 100))
			IEex_WriteDword(animationData + 0x10, math.floor(IEex_ReadDword(animationData + 0x10) * parameter1 / 100))
			IEex_WriteDword(animationData + 0x14, math.floor(IEex_ReadDword(animationData + 0x14) * parameter1 / 100))
		end
	else
		if parameter2 == 0 then
			IEex_WriteByte(animationData + 0x3E4, IEex_ReadByte(animationData + 0x3E4, 0x0) + parameter1)
		elseif parameter2 == 1 then
			IEex_WriteByte(animationData + 0x3E4, parameter1)
		elseif parameter2 == 2 then
			IEex_WriteByte(animationData + 0x3E4, math.floor(IEex_ReadByte(animationData + 0x3E4, 0x0) * parameter1 / 100))
		end
	end
end

function MEFINDTR(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if IEex_GetActorShare(sourceID) <= 0 then return end
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local special = IEex_ReadDword(effectData + 0x44)
	local targetx = IEex_ReadDword(effectData + 0x84)
	local targety = IEex_ReadDword(effectData + 0x88)
	if targetx <= 0 or targety <= 0 then
		targetx = IEex_ReadDword(creatureData + 0x6)
		targety = IEex_ReadDword(creatureData + 0xA)
	end
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local areaData = IEex_ReadDword(creatureData + 0x12)
	local autoPause = false
	IEex_IterateIDs(areaData, 0x11, function(id)
		local containerData = IEex_GetActorShare(id)
		if special <= 0 or IEex_GetDistance(targetx, targety, IEex_ReadDword(containerData + 0x6), IEex_ReadDword(containerData + 0xA)) < special then
			if bit.band(IEex_ReadDword(containerData + 0x88E), 0x20) == 0 and IEex_ReadWord(containerData + 0x892, 0x0) ~= 100 and IEex_ReadWord(containerData + 0x896, 0x0) > 0 then
				if IEex_ReadWord(containerData + 0x898, 0x0) == 0 then
					autoPause = true
					IEex_WriteWord(containerData + 0x898, 1)
				end
				IEex_WriteWord(containerData + 0x8D0, 362)
			end
		end
	end)
	IEex_IterateIDs(areaData, 0x21, function(id)
		local doorData = IEex_GetActorShare(id)
		if special <= 0 or IEex_GetDistance(targetx, targety, IEex_ReadDword(doorData + 0x6), IEex_ReadDword(doorData + 0xA)) < special then
			local doorFlags = IEex_ReadDword(doorData + 0x5C4)
			if bit.band(doorFlags, 0x8) > 0 and (bit.band(doorFlags, 0x80) == 0 or bit.band(doorFlags, 0x100) > 0) and bit.band(doorFlags, 0x2000) == 0 and IEex_ReadWord(doorData + 0x648, 0x0) ~= 100 and IEex_ReadWord(doorData + 0x64C, 0x0) > 0 then
				if IEex_ReadWord(doorData + 0x64E, 0x0) == 0 then
					autoPause = true
					IEex_WriteWord(doorData + 0x64E, 1)
				end
				IEex_WriteWord(doorData + 0x664, 362)
			end
		end
	end)
	IEex_IterateIDs(areaData, 0x41, function(id)
		local triggerData = IEex_GetActorShare(id)
		if special <= 0 or IEex_GetDistance(targetx, targety, IEex_ReadDword(triggerData + 0x6), IEex_ReadDword(triggerData + 0xA)) < special then
			local triggerFlags = IEex_ReadDword(triggerData + 0x5D6)
			if IEex_ReadWord(triggerData + 0x598, 0x0) == 0 and bit.band(triggerFlags, 0x8) > 0 and bit.band(triggerFlags, 0x100) == 0 and IEex_ReadWord(triggerData + 0x60E, 0x0) ~= 100 and IEex_ReadWord(triggerData + 0x612, 0x0) > 0 then
				if IEex_ReadWord(triggerData + 0x614, 0x0) == 0 then
					autoPause = true
					IEex_WriteWord(triggerData + 0x614, 1)
				end
				IEex_WriteWord(triggerData + 0x626, 263)
			end
		end
	end)
	if autoPause then
		IEex_Call(IEex_ReadDword(IEex_ReadDword(creatureData) + 0xB0), {0x80}, creatureData, 0x0)
	end
end

function MENPCXP(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local sourceData = IEex_GetActorShare(sourceID)
	if sourceData <= 0 then return end
	local special = IEex_ReadDword(effectData + 0x44)
	local totalXP = 0
	local slotID = 0
	local slotCount = 0
	for i = 0, 5, 1 do
		slotID = IEex_GetActorIDCharacter(i)
		if slotID > 0 and slotID ~= sourceID then
			slotCount = slotCount + 1
			totalXP = totalXP + IEex_ReadDword(IEex_GetActorShare(slotID) + 0x5B4)
		end
	end
	if special == 0 and slotCount > 0 then
		IEex_WriteDword(sourceData + 0x5B4, math.floor(totalXP / slotCount))
	elseif special == 1 then
		IEex_WriteDword(sourceData + 0x5B4, math.floor(totalXP / 5))
	end
end

function MENOSUST(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	IEex_WriteDword(creatureData + 0x5BC, bit.band(IEex_ReadDword(creatureData + 0x5BC), 0xEFFFFFFF))
	IEex_WriteDword(creatureData + 0x920, bit.band(IEex_ReadDword(creatureData + 0x920), 0xEFFFFFFF))
end
--[[
function MESUCREA(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if sourceID <= 0 then return end
	local sourceData = IEex_GetActorShare(sourceID)
	if sourceData == 0 then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local creatureName = IEex_ReadLString(sourceData + 0x598, 8)
	local isReload = false
	if creatureName == "" then 
		isReload = true
	end
	local targetIsSummoner = false
	local targetIsFiendSummoner = false
	local hasFoundSummoner = IEex_ReadByte(sourceData + 0x730, 0x0)
	if hasFoundSummoner ~= 0 and (hasFoundSummoner == -1 or hasFoundSummoner == 255 or creatureName == "") then
		hasFoundSummoner = 0
		IEex_WriteByte(sourceData + 0x730, 0)
	end
	local summonNumber = IEex_ReadSignedWord(sourceData + 0x732, 0x0)
	if summonNumber == -1 then
		summonNumber = 0
		IEex_WriteWord(sourceData + 0x732, summonNumber)
	end
	if hasFoundSummoner == 0 and IEex_GetActorSpellState(targetID, 207) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local theparameter3 = IEex_ReadWord(eData + 0x60, 0x0)
			if targetIsSummoner == false and theopcode == 288 and theparameter2 == 207 and (theresource == creatureName or summonNumber > 0) and (isReload == false or theparameter3 == summonNumber) and (isReload or theparameter1 > 0) then
				IEex_WriteLString(sourceData + 0x598, theresource, 8)
				if theparameter1 > 0 then
					IEex_WriteDword(eData + 0x1C, theparameter1 - 1)
				end
				if theparameter3 > 0 then
					summonNumber = theparameter3
				elseif summonNumber == 0 then
					summonNumber = math.random(32767)
					IEex_WriteDword(eData + 0x60, summonNumber)
				end
				IEex_WriteWord(sourceData + 0x732, summonNumber)
				targetIsSummoner = true
				targetIsFiendSummoner = (bit.band(IEex_ReadDword(eData + 0x40), 0x100000) > 0)
				IEex_WriteDword(sourceData + 0x72C, targetID)
				hasFoundSummoner = 1
				IEex_WriteByte(sourceData + 0x730, hasFoundSummoner)
			end
		end)
	end

	if targetIsSummoner and IEex_GetActorSpellState(targetID, 228) then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 228 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				local applyOnReload = (bit.band(thesavingthrow, 0x100000) > 0)
				local matchRace = IEex_ReadByte(eData + 0x48, 0x0)
				local spellRES = IEex_ReadLString(eData + 0x30, 8)
				if spellRES ~= "" and (matchRace == 0 or matchRace == IEex_ReadByte(sourceData + 0x26, 0x0)) and (isReload == false or applyOnReload == true) then
					local casterLevel = IEex_ReadDword(effectData + 0xC4)
					if casterLevel == 0 then
						casterLevel = 1
					end
					local newEffectTarget = sourceID
					local newEffectTargetX = IEex_ReadDword(effectData + 0x7C)
					local newEffectTargetY = IEex_ReadDword(effectData + 0x80)
					if (bit.band(thesavingthrow, 0x200000) > 0) then
						newEffectTarget = targetID
						newEffectTargetX = IEex_ReadDword(effectData + 0x84)
						newEffectTargetY = IEex_ReadDword(effectData + 0x88)
					end
					local newEffectSource = targetID
					local newEffectSourceX = IEex_ReadDword(effectData + 0x84)
					local newEffectSourceY = IEex_ReadDword(effectData + 0x88)
					if (bit.band(thesavingthrow, 0x400000) > 0) then
						newEffectSource = sourceID
						newEffectSourceX = IEex_ReadDword(effectData + 0x7C)
						newEffectSourceY = IEex_ReadDword(effectData + 0x80)
					end
					if isReload == false then
						local usesLeft = IEex_ReadByte(eData + 0x49, 0x0)
						if usesLeft == 1 then
							local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
							IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = theparent_resource,
["source_id"] = sourceID
})
						elseif usesLeft > 0 then
							usesLeft = usesLeft - 1
							IEex_WriteByte(eData + 0x49, usesLeft)
						end
					end
					IEex_ApplyEffectToActor(newEffectTarget, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["source_x"] = newEffectSourceX,
["source_y"] = newEffectSourceY,
["target_x"] = newEffectTargetX,
["target_y"] = newEffectTargetY,
["casterlvl"] = casterLevel,
["parent_resource"] = spellRES,
["source_target"] = newEffectTarget,
["source_id"] = newEffectSource
})
				end
			end
		end)
	end
	if targetIsFiendSummoner and isReload == false then
		local summonerIsEnemy = false
		local summonerAllegiance = IEex_ReadByte(creatureData + 0x24, 0x0)
		if summonerAllegiance == 255 or summonerAllegiance == 254 or summonerAllegiance == 200 then
			summonerIsEnemy = true
		end
		local summonerHasProtection = IEex_GetActorSpellState(targetID, 1)

		if (summonerIsEnemy and summonerHasProtection) or (summonerIsEnemy == false and summonerHasProtection == false) then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USPCFIEN",
["source_id"] = sourceID
})
		else
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 208,
["parent_resource"] = "USPCFIEN",
["source_id"] = sourceID
})
		end
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 1,
["parameter2"] = 224,
["resource"] = "USEAFIEN",
["parent_resource"] = "USEAFIEN",
["source_id"] = sourceID
})
	end
end
--]]
ex_generic_default_actionbar = {5, 11, 4, 3, 14, 80, 81, 82, 10}
function MESUCREA(effectData, creatureData)
--	IEex_WriteDword(effectData + 0x110, 1)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(sourceID, false) then return end
	local summonerID = IEex_GetActorSummonerID(sourceID)
	if not IEex_IsSprite(summonerID, true) then return end
	local summonerData = IEex_GetActorShare(summonerID)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if IEex_ReadDword(effectData + 0x10C) <= 0 or bit.band(internalFlags, 0x10) == 0 then
		IEex_WriteDword(effectData + 0x10C, summonerID)
		IEex_WriteDword(effectData + 0xD4, bit.bor(internalFlags, 0x10))
	else
		return
	end
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if bit.band(savingthrow, 0x20000) == 0 then
		for k, v in ipairs(ex_generic_default_actionbar) do
			IEex_WriteDword(creatureData + 0x3D10 + k * 0x4, v)
		end
	end
	local creatureName = IEex_ReadLString(creatureData + 0x598, 8)
	local isReload = false
	if creatureName == "" then 
		isReload = true
	end
	if IEex_GetActorSpellState(summonerID, 228) then
		IEex_IterateActorEffects(summonerID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theopcode == 288 and theparameter2 == 228 then
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				local applyOnReload = (bit.band(thesavingthrow, 0x100000) > 0)
				local matchRace = IEex_ReadByte(eData + 0x48, 0x0)
				local spellRES = IEex_ReadLString(eData + 0x30, 8)
				if spellRES ~= "" and (matchRace == 0 or matchRace == IEex_ReadByte(creatureData + 0x26, 0x0)) and (isReload == false or applyOnReload == true) then
					local casterLevel = IEex_ReadDword(effectData + 0xC4)
					if casterLevel == 0 then
						casterLevel = 1
					end
					local newEffectTarget = sourceID
					local newEffectTargetX = IEex_ReadDword(effectData + 0x7C)
					local newEffectTargetY = IEex_ReadDword(effectData + 0x80)
					if (bit.band(thesavingthrow, 0x200000) > 0) then
						newEffectTarget = summonerID
						newEffectTargetX = IEex_ReadDword(effectData + 0x84)
						newEffectTargetY = IEex_ReadDword(effectData + 0x88)
					end
					local newEffectSource = summonerID
					local newEffectSourceX = IEex_ReadDword(effectData + 0x84)
					local newEffectSourceY = IEex_ReadDword(effectData + 0x88)
					if (bit.band(thesavingthrow, 0x400000) > 0) then
						newEffectSource = sourceID
						newEffectSourceX = IEex_ReadDword(effectData + 0x7C)
						newEffectSourceY = IEex_ReadDword(effectData + 0x80)
					end
					if isReload == false then
						local usesLeft = IEex_ReadByte(eData + 0x49, 0x0)
						if usesLeft == 1 then
							local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
							IEex_ApplyEffectToActor(summonerID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = theparent_resource,
["source_id"] = sourceID
})
						elseif usesLeft > 0 then
							usesLeft = usesLeft - 1
							IEex_WriteByte(eData + 0x49, usesLeft)
						end
					end
					IEex_ApplyEffectToActor(newEffectTarget, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["source_x"] = newEffectSourceX,
["source_y"] = newEffectSourceY,
["target_x"] = newEffectTargetX,
["target_y"] = newEffectTargetY,
["casterlvl"] = casterLevel,
["parent_resource"] = spellRES,
["source_target"] = newEffectTarget,
["source_id"] = newEffectSource
})
				end
			end
		end)
	end
	local isSummonedFiend = (bit.band(IEex_ReadDword(creatureData + 0x740), 0x100000) > 0)
	if isSummonedFiend and isReload == false then
		local summonerIsEnemy = false
		local summonerAllegiance = IEex_ReadByte(summonerData + 0x24, 0x0)
		if summonerAllegiance == 255 or summonerAllegiance == 254 or summonerAllegiance == 200 then
			summonerIsEnemy = true
		end
		local summonerHasProtection = IEex_GetActorSpellState(summonerID, 1)

		if (summonerIsEnemy and summonerHasProtection) or (summonerIsEnemy == false and summonerHasProtection == false) then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USPCFIEN",
["source_id"] = sourceID
})
		else
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 208,
["parent_resource"] = "USPCFIEN",
["source_id"] = sourceID
})
		end
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 1,
["parameter2"] = 224,
["resource"] = "USEAFIEN",
["parent_resource"] = "USEAFIEN",
["source_id"] = sourceID
})
	end
end

function MEEAFIEN(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	local summonerID = IEex_GetActorSummonerID(sourceID)
	if not IEex_IsSprite(summonerID, false) then 
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USPCFIEN",
["source_id"] = sourceID
})
		return
	end
	local summonerData = IEex_GetActorShare(summonerID)
	local summonerIsEnemy = false
	local summonerAllegiance = IEex_ReadByte(summonerData + 0x24, 0x0)
	if summonerAllegiance == 255 or summonerAllegiance == 254 or summonerAllegiance == 200 then
		summonerIsEnemy = true
	end
	local summonerHasProtection = IEex_GetActorSpellState(summonerID, 1)

	if (summonerIsEnemy and summonerHasProtection) or (summonerIsEnemy == false and summonerHasProtection == false) then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USPCFIEN",
["source_id"] = sourceID
})
	elseif IEex_GetActorSpellState(sourceID, 208) == false then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 208,
["parent_resource"] = "USPCFIEN",
["source_id"] = sourceID
})
	end
end

ex_simulacrum_copied_fields = {
{0x24, 0x28, 1},
{0x34, 0x35, 1},
{0x38, 0x38, 4},
{0x5C8, 0x5CE, 1},
{0x5E2, 0x5EA, 2},
{0x5F0, 0x604, 1},
{0x648, 0x6FC, 4},
{0x758, 0x758, 2},
{0x75C, 0x770, 4},
{0x774, 0x7B3, 1},
{0x7B4, 0x7C3, 1},
{0x7F7, 0x807, 1},
{0x80C, 0x80C, 4},
{0x89F, 0x89F, 1},
{0x962, 0x962, 4},
{0x17BA, 0x17BA, 4},
{0x3E12, 0x3E12, 4},
{0x3E4E, 0x3E4E, 4},
}

ex_caster_type_spell_slots = {
{"MXSPLBRD", 42},
{"MXSPLCLR", 39},
{"MXSPLDRD", 39},
{"MXSPLPAL", 39},
{"MXSPLRGR", 39},
{"MXSPLSOR", 42},
{"MXSPLWIZ", 38},
}
function MESIMULA(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MESIMULA", 3) then return end
	local summonerID = IEex_GetActorSummonerID(targetID)
	local summonerData = IEex_GetActorShare(summonerID)
	if not IEex_IsSprite(summonerID, false) then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 6,
["duration"] = IEex_GetGameTick() + 1,
["resource"] = "MESIMULA",
["source_target"] = targetID,
["source_id"] = targetID
})

		return
	end
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	extraFlags = bit.bor(extraFlags, 0x400000)
	IEex_WriteDword(creatureData + 0x740, extraFlags)
	local newHP = math.ceil(IEex_ReadSignedWord(summonerData + 0x5C2, 0x0) / 2)
--	IEex_WriteWord(creatureData + 0x5C0, newHP)
--	IEex_WriteWord(creatureData + 0x5C2, newHP)
	local newLevelTotal = 0
--[[
	local casterTypes = {9, }
	local newCasterLevels = {0, 0, 0, 0, 0, 0, 0, 0}
	local newSpellSlots = {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, }
--]]
	for iClass = 1, 11, 1 do
		local newLevel = math.ceil(IEex_ReadByte(summonerData + 0x626 + iClass, 0x0) / 2)
		newLevelTotal = newLevelTotal + newLevel
		IEex_WriteByte(creatureData + 0x626 + iClass, newLevel)
--[[
		local iCasterType = IEex_CasterClassToType[iClass]
		if newLevel > 0 and iCasterType ~= nil then
			table.insert(casterTypes, IEex_CasterClassToType[iClass])
			newCasterLevels[iCasterType] = newLevel
			if iClass == 3 then
				table.insert(casterTypes, 8)
				newCasterLevels[8] = newLevel
			end
		end
--]]
	end
	IEex_WriteByte(creatureData + 0x626, newLevelTotal)
	for k, offset in ipairs(ex_simulacrum_copied_fields) do
		if offset[3] == 1 then
			for i = offset[1], offset[2], 1 do
				IEex_WriteByte(creatureData + i, IEex_ReadSignedByte(summonerData + i, 0x0))
			end
		elseif offset[3] == 2 then
			for i = offset[1], offset[2], 2 do
				IEex_WriteWord(creatureData + i, IEex_ReadSignedWord(summonerData + i, 0x0))
			end
		elseif offset[3] == 4 then
			for i = offset[1], offset[2], 4 do
				IEex_WriteDword(creatureData + i, IEex_ReadDword(summonerData + i))
			end
		else
			for i = offset[1], offset[2], offset[3] do
				IEex_WriteLString(creatureData + i, IEex_ReadLString(summonerData + i, offset[3]), offset[3])
			end
		end
	end
	for i = 0, 50, 1 do
		if i <= 8 or i >= 42 then
			local currentSlotRES = IEex_GetItemSlotRES(summonerID, i)
			local resWrapper = IEex_DemandRes(currentSlotRES, "ITM")
			if resWrapper:isValid() then
				if bit.band(IEex_ReadDword(resWrapper:getData() + 0x18), 0x4) == 0 then
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = i,
["resource"] = currentSlotRES,
["source_id"] = targetID
})
				end
			end
			resWrapper:free()
		end
	end
	IEex_IterateActorEffects(summonerID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local thetiming = IEex_ReadDword(eData + 0x24)
		if thetiming == 9 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = IEex_ReadDword(eData + 0x10),
["target"] = IEex_ReadDword(eData + 0x14),
["power"] = IEex_ReadDword(eData + 0x18),
["parameter1"] = IEex_ReadDword(eData + 0x1C),
["parameter2"] = IEex_ReadDword(eData + 0x20),
["timing"] = IEex_ReadDword(eData + 0x24),
["duration"] = IEex_ReadDword(eData + 0x28),
["resource"] = IEex_ReadLString(eData + 0x30, 8),
["dicenumber"] = IEex_ReadDword(eData + 0x38),
["dicesize"] = IEex_ReadDword(eData + 0x3C),
["savingthrow"] = IEex_ReadDword(eData + 0x40),
["savebonus"] = IEex_ReadDword(eData + 0x44),
["special"] = IEex_ReadDword(eData + 0x48),
["school"] = IEex_ReadDword(eData + 0x4C),
["parameter3"] = IEex_ReadDword(eData + 0x60),
["parameter4"] = IEex_ReadDword(eData + 0x64),
["parameter5"] = IEex_ReadDword(eData + 0x68),
["time_applied"] = IEex_ReadDword(eData + 0x6C),
["vvcresource"] = IEex_ReadLString(eData + 0x70, 8),
["resource2"] = IEex_ReadLString(eData + 0x78, 8),
["source_x"] = IEex_ReadDword(eData + 0x80),
["source_y"] = IEex_ReadDword(eData + 0x84),
["target_x"] = IEex_ReadDword(eData + 0x88),
["target_y"] = IEex_ReadDword(eData + 0x8C),
["restype"] = IEex_ReadDword(eData + 0x90),
["parent_resource"] = IEex_ReadLString(eData + 0x94, 8),
["resource_flags"] = bit.band(IEex_ReadDword(eData + 0x9C), 0xFFFFF9FF),
["impact_projectile"] = IEex_ReadDword(eData + 0xA0),
["sourceslot"] = IEex_ReadDword(eData + 0xA4),
["effvar"] = IEex_ReadLString(eData + 0xA8, 32),
["casterlvl"] = IEex_ReadDword(eData + 0xC8),
["internal_flags"] = IEex_ReadDword(eData + 0xD8),
["sectype"] = IEex_ReadDword(eData + 0xD8),
["source_id"] = IEex_ReadDword(eData + 0x110),
})
		end
	end)
	
--[[
	for iCasterType = 1, 7, 1 do
		local newLevel = newCasterLevels[iCasterType]
		if newLevel > 0 then
			for iLevel = 1, 9, 1 do
				local numSlots = tonumber(IEex_2DAGetAtStrings(ex_caster_type_spell_slots[iCasterType][1], tostring(iLevel), tostring(newLevel)))
				if numSlots > 0 then
					numSlots = numSlots + tonumber(IEex_2DAGetAtStrings("MXSPLBON", tostring(iLevel), tostring(IEex_GetActorStat(summonerID, ex_caster_type_spell_slots[iCasterType][2]))))
					if iCasterType == 3 then
						newSpellSlots[8][iLevel] = 1
					end
				end
				newSpellSlots[iCasterType][iLevel] = numSlots
			end
		end
	end
	local summonerSpells = IEex_FetchSpellInfo(summonerID, casterTypes)
	for cType, levelList in pairs(summonerSpells) do
		for i = 1, 9, 1 do
			if #levelList >= i then
				local numSlots = 0
				if newSpellSlots[cType] ~= nil and newSpellSlots[cType][i] ~= nil then
					numSlots = newSpellSlots[cType][i]
				end
				local levelI = levelList[i]
				local maxCastable = levelI[1]
				local sorcererCastableCount = levelI[2]
				local levelISpells = levelI[3]
				if levelISpells ~= nil and #levelISpells > 0 then
					if cType == 1 or cType == 6 then
						if numSlots > sorcererCastableCount then
							numSlots = sorcererCastableCount
						end
						if numSlots > 0 then
							IEex_AlterSpellInfo(targetID, cType, i, "", numSlots, numSlots)
							for i2, spell in ipairs(levelISpells) do
								IEex_AlterSpellInfo(targetID, cType, i, spell["resref"], numSlots, numSlots)
							end
							IEex_AlterSpellInfo(targetID, cType, i, "", numSlots, numSlots)
						end
					elseif cType <= 8 then
						if numSlots > 0 then
							for i2, spell in ipairs(levelISpells) do
								local castableCount = spell["castableCount"]
								if castableCount > numSlots then
									castableCount = numSlots
								end
								if castableCount > 0 then
									IEex_AlterSpellInfo(targetID, cType, i, spell["resref"], castableCount, castableCount)
									numSlots = numSlots - castableCount
								end
							end
						end
					end
				end
			end
		end
	end
	if summonerSpells[9] ~= nil and summonerSpells[9][1] ~= nil then
		local levelISpells = summonerSpells[9][1]
		for i2, spell in ipairs(levelISpells) do
			local castableCount = spell["castableCount"]
			if castableCount > 0 then
				IEex_AlterSpellInfo(targetID, 9, 1, spell["resref"], spell["memorizedCount"], castableCount)
			end
		end
	end
--]]
	if newHP > 10 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 18,
["target"] = 2,
["timing"] = 1,
["parameter1"] = newHP - 10,
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 1,
["parameter1"] = IEex_ReadDword(summonerData + 0x5C4),
["parameter2"] = 2,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter1"] = IEex_ReadDword(summonerData + 0x5C4),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["parameter1"] = buttonIndex,
["parameter2"] = 222,
["savingthrow"] = 0x8500000,
["resource"] = "USWI862E",
["source_id"] = targetID
})
	for buttonIndex = 0, 8, 1 do
		local buttonType = IEex_ReadDword(summonerData + 0x3D14 + buttonIndex * 0x4)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["parameter1"] = buttonIndex,
["parameter2"] = buttonType,
["resource"] = "EXBUTTON",
["source_id"] = targetID
})
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 3,
["duration"] = 1,
["parameter1"] = summonerID,
["resource"] = "MESIMUL2",
["source_target"] = targetID,
["source_id"] = targetID
})
end

function MESIMUL2(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local summonerID = IEex_ReadDword(effectData + 0x18)
	local summonerData = IEex_GetActorShare(summonerID)
	if not IEex_IsSprite(summonerID, false) then return end
	local newLevelTotal = 0
	local casterTypes = {9, }
	local newCasterLevels = {0, 0, 0, 0, 0, 0, 0, 0}
	local newSpellSlots = {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, }
	for iClass = 1, 11, 1 do
		local newLevel = IEex_ReadByte(creatureData + 0x626 + iClass, 0x0)
		local iCasterType = IEex_CasterClassToType[iClass]
		if newLevel > 0 and iCasterType ~= nil then
			table.insert(casterTypes, IEex_CasterClassToType[iClass])
			newCasterLevels[iCasterType] = newLevel
			if iClass == 3 then
				table.insert(casterTypes, 8)
				newCasterLevels[8] = newLevel
			end
		end
	end
	for iCasterType = 1, 7, 1 do
		local newLevel = newCasterLevels[iCasterType]
		if newLevel > 0 then
			for iLevel = 1, 9, 1 do
				local numSlots = tonumber(IEex_2DAGetAtStrings(ex_caster_type_spell_slots[iCasterType][1], tostring(iLevel), tostring(newLevel)))
				if numSlots > 0 then
					numSlots = numSlots + tonumber(IEex_2DAGetAtStrings("MXSPLBON", tostring(iLevel), tostring(IEex_GetActorStat(summonerID, ex_caster_type_spell_slots[iCasterType][2]))))
					if iCasterType == 2 then
						newSpellSlots[8][iLevel] = 1
					end
				end
				newSpellSlots[iCasterType][iLevel] = numSlots
			end
		end
	end
	local summonerSpells = IEex_FetchSpellInfo(summonerID, casterTypes)
	for cType, levelList in pairs(summonerSpells) do
		for i = 1, 9, 1 do
			if #levelList >= i then
				local numSlots = 0
				if newSpellSlots[cType] ~= nil and newSpellSlots[cType][i] ~= nil then
					numSlots = newSpellSlots[cType][i]
				end
				local levelI = levelList[i]
				local maxCastable = levelI[1]
				local sorcererCastableCount = levelI[2]
				local levelISpells = levelI[3]
				if levelISpells ~= nil and #levelISpells > 0 then
					if cType == 1 or cType == 6 then
						if numSlots > sorcererCastableCount then
							numSlots = sorcererCastableCount
						end
						if numSlots > 0 then
--							IEex_AlterSpellInfo(targetID, cType, i, "", numSlots, numSlots)
							for i2, spell in ipairs(levelISpells) do
								IEex_AlterSpellInfo(targetID, cType, i, spell["resref"], numSlots, numSlots)
							end
							IEex_AlterSpellInfo(targetID, cType, i, "", numSlots, numSlots)
						end
					elseif cType <= 8 then
						if numSlots > 0 then
							for i2, spell in ipairs(levelISpells) do
								local castableCount = spell["castableCount"]
								if castableCount > numSlots then
									castableCount = numSlots
								end
								if castableCount > 0 then
									IEex_AlterSpellInfo(targetID, cType, i, spell["resref"], castableCount, castableCount)
									numSlots = numSlots - castableCount
								end
							end
						end
					end
				end
			end
		end
	end
	if summonerSpells[9] ~= nil and summonerSpells[9][1] ~= nil then
		local levelISpells = summonerSpells[9][1]
		for i2, spell in ipairs(levelISpells) do
			local castableCount = spell["castableCount"]
			if castableCount > 0 then
				IEex_AlterSpellInfo(targetID, 9, 1, spell["resref"], spell["memorizedCount"], castableCount)
			end
		end
	end
end
ex_clone_summoner_to_identity = {}
function MECLONE(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	IEex_WriteDword(effectData + 0x110, 1)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local sourceX, sourceY = IEex_GetActorLocation(sourceID)
	local targetID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsPartyMember(targetID) then
		return
	end
	local ids = {}
	if IEex_ReadDword(creatureData + 0x12) > 0 then
		ids = IEex_GetIDArea(sourceID, 0x31)
	end
	for k, currentID in ipairs(ids) do
		local currentShare = IEex_GetActorShare(currentID)
		if currentShare > 0 then
			local extraFlags = IEex_ReadDword(currentShare + 0x740)
			local currentSummonerID = IEex_GetActorSummonerID(currentID)
			if bit.band(extraFlags, 0x80000) > 0 and currentSummonerID == targetID then
				return
			end
		end
	end
	ex_clone_summoner_to_identity["" .. sourceID] = IEex_ReadDword(creatureData + 0x700)
	local timing = 9
	local duration = IEex_ReadDword(effectData + 0x24)
	if duration > 0 then
		timing = 0
	end
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 410,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter1"] = 1,
["resource"] = "USCLONE",
["savingthrow"] = 0x30000,
["target_x"] = sourceX,
["target_y"] = sourceY,
["source_id"] = sourceID
})
end

function MECLONE2(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MESIMULA", 3) then return end
	local summonerID = IEex_GetActorSummonerID(targetID)
	local realSummonerConstantID = ex_clone_summoner_to_identity["" .. summonerID]
	if realSummonerConstantID then
		IEex_WriteDword(creatureData + 0x72C, realSummonerConstantID)
		ex_clone_summoner_to_identity["" .. summonerID] = nil
		summonerID = IEex_Helper_GetBridge("IEex_ConstantID", realSummonerConstantID)
	end
	local summonerData = IEex_GetActorShare(summonerID)
	if not IEex_IsSprite(summonerID, true) then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 6,
["duration"] = IEex_GetGameTick() + 1,
["resource"] = "MECLONE2",
["source_target"] = targetID,
["source_id"] = targetID
})

		return
	end
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	extraFlags = bit.bor(extraFlags, 0x80000)
	IEex_WriteDword(creatureData + 0x740, extraFlags)
	local newHP = IEex_ReadSignedWord(summonerData + 0x5C2, 0x0)
--	IEex_WriteWord(creatureData + 0x5C0, newHP)
--	IEex_WriteWord(creatureData + 0x5C2, newHP)
	local newLevelTotal = 0
--[[
	local casterTypes = {9, }
	local newCasterLevels = {0, 0, 0, 0, 0, 0, 0, 0}
	local newSpellSlots = {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, }
--]]
	for iClass = 1, 11, 1 do
		local newLevel = IEex_ReadByte(summonerData + 0x626 + iClass, 0x0)
		newLevelTotal = newLevelTotal + newLevel
		IEex_WriteByte(creatureData + 0x626 + iClass, newLevel)
--[[
		local iCasterType = IEex_CasterClassToType[iClass]
		if newLevel > 0 and iCasterType ~= nil then
			table.insert(casterTypes, IEex_CasterClassToType[iClass])
			newCasterLevels[iCasterType] = newLevel
			if iClass == 3 then
				table.insert(casterTypes, 8)
				newCasterLevels[8] = newLevel
			end
		end
--]]
	end
	IEex_WriteByte(creatureData + 0x626, newLevelTotal)
	for k, offset in ipairs(ex_simulacrum_copied_fields) do
		if offset[3] == 1 then
			for i = offset[1], offset[2], 1 do
				IEex_WriteByte(creatureData + i, IEex_ReadSignedByte(summonerData + i, 0x0))
			end
		elseif offset[3] == 2 then
			for i = offset[1], offset[2], 2 do
				IEex_WriteWord(creatureData + i, IEex_ReadSignedWord(summonerData + i, 0x0))
			end
		elseif offset[3] == 4 then
			for i = offset[1], offset[2], 4 do
				IEex_WriteDword(creatureData + i, IEex_ReadDword(summonerData + i))
			end
		else
			for i = offset[1], offset[2], offset[3] do
				IEex_WriteLString(creatureData + i, IEex_ReadLString(summonerData + i, offset[3]), offset[3])
			end
		end
	end
	for i = 0, 50, 1 do
		if i <= 8 or i >= 42 then
			local currentSlotRES = IEex_GetItemSlotRES(summonerID, i)
			local resWrapper = IEex_DemandRes(currentSlotRES, "ITM")
			if resWrapper:isValid() then
				if bit.band(IEex_ReadDword(resWrapper:getData() + 0x18), 0x4) == 0 then
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = i,
["resource"] = currentSlotRES,
["source_id"] = targetID
})
				end
			end
			resWrapper:free()
		end
	end
	if newHP > 10 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 18,
["target"] = 2,
["timing"] = 1,
["parameter1"] = newHP - 10,
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
	end
	IEex_IterateActorEffects(summonerID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local thetiming = IEex_ReadDword(eData + 0x24)
		if thetiming == 9 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = IEex_ReadDword(eData + 0x10),
["target"] = IEex_ReadDword(eData + 0x14),
["power"] = IEex_ReadDword(eData + 0x18),
["parameter1"] = IEex_ReadDword(eData + 0x1C),
["parameter2"] = IEex_ReadDword(eData + 0x20),
["timing"] = IEex_ReadDword(eData + 0x24),
["duration"] = IEex_ReadDword(eData + 0x28),
["resource"] = IEex_ReadLString(eData + 0x30, 8),
["dicenumber"] = IEex_ReadDword(eData + 0x38),
["dicesize"] = IEex_ReadDword(eData + 0x3C),
["savingthrow"] = IEex_ReadDword(eData + 0x40),
["savebonus"] = IEex_ReadDword(eData + 0x44),
["special"] = IEex_ReadDword(eData + 0x48),
["school"] = IEex_ReadDword(eData + 0x4C),
["parameter3"] = IEex_ReadDword(eData + 0x60),
["parameter4"] = IEex_ReadDword(eData + 0x64),
["parameter5"] = IEex_ReadDword(eData + 0x68),
["time_applied"] = IEex_ReadDword(eData + 0x6C),
["vvcresource"] = IEex_ReadLString(eData + 0x70, 8),
["resource2"] = IEex_ReadLString(eData + 0x78, 8),
["source_x"] = IEex_ReadDword(eData + 0x80),
["source_y"] = IEex_ReadDword(eData + 0x84),
["target_x"] = IEex_ReadDword(eData + 0x88),
["target_y"] = IEex_ReadDword(eData + 0x8C),
["restype"] = IEex_ReadDword(eData + 0x90),
["parent_resource"] = IEex_ReadLString(eData + 0x94, 8),
["resource_flags"] = bit.band(IEex_ReadDword(eData + 0x9C), 0xFFFFF9FF),
["impact_projectile"] = IEex_ReadDword(eData + 0xA0),
["sourceslot"] = IEex_ReadDword(eData + 0xA4),
["effvar"] = IEex_ReadLString(eData + 0xA8, 32),
["casterlvl"] = IEex_ReadDword(eData + 0xC8),
["internal_flags"] = IEex_ReadDword(eData + 0xD8),
["sectype"] = IEex_ReadDword(eData + 0xD8),
["source_id"] = IEex_ReadDword(eData + 0x110),
})
		end
	end)
	if newHP > 10 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 18,
["target"] = 2,
["timing"] = 1,
["parameter1"] = newHP - 10,
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 1,
["parameter1"] = IEex_ReadDword(summonerData + 0x5C4),
["parameter2"] = 2,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter1"] = IEex_ReadDword(summonerData + 0x5C4),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
--[[
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["parameter1"] = buttonIndex,
["parameter2"] = 222,
["savingthrow"] = 0x8500000,
["resource"] = "USWI862E",
["source_id"] = targetID
})
--]]
--[[
	for buttonIndex = 0, 8, 1 do
		local buttonType = IEex_ReadDword(summonerData + 0x3D14 + buttonIndex * 0x4)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["parameter1"] = buttonIndex,
["parameter2"] = buttonType,
["resource"] = "EXBUTTON",
["source_id"] = targetID
})
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 3,
["duration"] = 1,
["parameter1"] = summonerID,
["resource"] = "MESIMUL2",
["source_target"] = targetID,
["source_id"] = targetID
})
--]]
end

function MECLONE3(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local summonerID = IEex_GetActorSummonerID(targetID)
	local summonerData = IEex_GetActorShare(summonerID)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	if summonerData <= 0 then return end
	local summonerState = IEex_ReadDword(summonerData + 0x5BC)
	if bit.band(summonerState, 0xF00) == 0 or bit.band(summonerState, 0xC0) > 0 then return end
	if (IEex_GetGameTick() - time_applied) < (ex_clone_delay * 15) then
		return
	end
	local areaData = IEex_ReadDword(creatureData + 0x12)
	local summonerAreaData = IEex_ReadDword(summonerData + 0x12)
--	if areaData ~= summonerAreaData then return end
	IEex_WriteDword(effectData + 0x110, 1)
--[[
	IEex_ApplyEffectToActor(summonerID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["resource"] = "MERAISED",
["savingthrow"] = 0x20000,
["source_id"] = targetID
})
--]]
	IEex_ApplyEffectToActor(summonerID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 9,
["resource"] = "USWI866D",
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(summonerID, {
["opcode"] = 17,
["target"] = 2,
["timing"] = 1,
["parameter1"] = IEex_ReadSignedWord(creatureData + 0x5C0, 0x0),
["parameter2"] = 1,
["source_id"] = targetID
})
	local targetX, targetY = IEex_GetActorLocation(targetID)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 168,
["target"] = 2,
["timing"] = 9,
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(summonerID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["resource"] = "MENOTEL",
["target_x"] = targetX,
["target_y"] = targetY,
["source_id"] = summonerID
})
	IEex_WriteByte(summonerData + 0x9DC, 1)
	IEex_ApplyEffectToActor(summonerID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 9,
["target_x"] = targetX,
["target_y"] = targetY,
["source_id"] = summonerID
})
end

function MEMISLEA(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MESIMULA", 3) then return end
	local summonerID = IEex_GetActorSummonerID(targetID)
	local summonerData = IEex_GetActorShare(summonerID)
	if not IEex_IsSprite(summonerID, false) then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 6,
["duration"] = IEex_GetGameTick() + 1,
["resource"] = "MESIMULA",
["source_target"] = targetID,
["source_id"] = targetID
})

		return
	end
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	extraFlags = bit.bor(extraFlags, 0x8000000)
	IEex_WriteDword(creatureData + 0x740, extraFlags)
	local newHP = math.ceil(IEex_ReadSignedWord(summonerData + 0x5C2, 0x0) / 2)
--	IEex_WriteWord(creatureData + 0x5C0, newHP)
--	IEex_WriteWord(creatureData + 0x5C2, newHP)
	local newLevelTotal = 0
	for iClass = 1, 11, 1 do
		local newLevel = math.ceil(IEex_ReadByte(summonerData + 0x626 + iClass, 0x0) / 2)
		newLevelTotal = newLevelTotal + newLevel
		IEex_WriteByte(creatureData + 0x626 + iClass, newLevel)
--[[
		local iCasterType = IEex_CasterClassToType[iClass]
		if newLevel > 0 and iCasterType ~= nil then
			table.insert(casterTypes, IEex_CasterClassToType[iClass])
			newCasterLevels[iCasterType] = newLevel
			if iClass == 3 then
				table.insert(casterTypes, 8)
				newCasterLevels[8] = newLevel
			end
		end
--]]
	end
	IEex_WriteByte(creatureData + 0x626, newLevelTotal)
	for k, offset in ipairs(ex_simulacrum_copied_fields) do
		if offset[3] == 1 then
			for i = offset[1], offset[2], 1 do
				IEex_WriteByte(creatureData + i, IEex_ReadSignedByte(summonerData + i, 0x0))
			end
		elseif offset[3] == 2 then
			for i = offset[1], offset[2], 2 do
				IEex_WriteWord(creatureData + i, IEex_ReadSignedWord(summonerData + i, 0x0))
			end
		elseif offset[3] == 4 then
			for i = offset[1], offset[2], 4 do
				IEex_WriteDword(creatureData + i, IEex_ReadDword(summonerData + i))
			end
		else
			for i = offset[1], offset[2], offset[3] do
				IEex_WriteLString(creatureData + i, IEex_ReadLString(summonerData + i, offset[3]), offset[3])
			end
		end
	end
	for i = 0, 50, 1 do
		if i <= 8 or i >= 42 then
			local currentSlotRES = IEex_GetItemSlotRES(summonerID, i)
			local resWrapper = IEex_DemandRes(currentSlotRES, "ITM")
			if resWrapper:isValid() then
				if bit.band(IEex_ReadDword(resWrapper:getData() + 0x18), 0x4) == 0 then
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = i,
["resource"] = currentSlotRES,
["source_id"] = targetID
})
				end
			end
			resWrapper:free()
		end
	end
	IEex_IterateActorEffects(summonerID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local thetiming = IEex_ReadDword(eData + 0x24)
		if thetiming == 9 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = IEex_ReadDword(eData + 0x10),
["target"] = IEex_ReadDword(eData + 0x14),
["power"] = IEex_ReadDword(eData + 0x18),
["parameter1"] = IEex_ReadDword(eData + 0x1C),
["parameter2"] = IEex_ReadDword(eData + 0x20),
["timing"] = IEex_ReadDword(eData + 0x24),
["duration"] = IEex_ReadDword(eData + 0x28),
["resource"] = IEex_ReadLString(eData + 0x30, 8),
["dicenumber"] = IEex_ReadDword(eData + 0x38),
["dicesize"] = IEex_ReadDword(eData + 0x3C),
["savingthrow"] = IEex_ReadDword(eData + 0x40),
["savebonus"] = IEex_ReadDword(eData + 0x44),
["special"] = IEex_ReadDword(eData + 0x48),
["school"] = IEex_ReadDword(eData + 0x4C),
["parameter3"] = IEex_ReadDword(eData + 0x60),
["parameter4"] = IEex_ReadDword(eData + 0x64),
["parameter5"] = IEex_ReadDword(eData + 0x68),
["time_applied"] = IEex_ReadDword(eData + 0x6C),
["vvcresource"] = IEex_ReadLString(eData + 0x70, 8),
["resource2"] = IEex_ReadLString(eData + 0x78, 8),
["source_x"] = IEex_ReadDword(eData + 0x80),
["source_y"] = IEex_ReadDword(eData + 0x84),
["target_x"] = IEex_ReadDword(eData + 0x88),
["target_y"] = IEex_ReadDword(eData + 0x8C),
["restype"] = IEex_ReadDword(eData + 0x90),
["parent_resource"] = IEex_ReadLString(eData + 0x94, 8),
["resource_flags"] = bit.band(IEex_ReadDword(eData + 0x9C), 0xFFFFF9FF),
["impact_projectile"] = IEex_ReadDword(eData + 0xA0),
["sourceslot"] = IEex_ReadDword(eData + 0xA4),
["effvar"] = IEex_ReadLString(eData + 0xA8, 32),
["casterlvl"] = IEex_ReadDword(eData + 0xC8),
["internal_flags"] = IEex_ReadDword(eData + 0xD8),
["sectype"] = IEex_ReadDword(eData + 0xD8),
["source_id"] = IEex_ReadDword(eData + 0x110),
})
		end
	end)
	
--[[
	for iCasterType = 1, 7, 1 do
		local newLevel = newCasterLevels[iCasterType]
		if newLevel > 0 then
			for iLevel = 1, 9, 1 do
				local numSlots = tonumber(IEex_2DAGetAtStrings(ex_caster_type_spell_slots[iCasterType][1], tostring(iLevel), tostring(newLevel)))
				if numSlots > 0 then
					numSlots = numSlots + tonumber(IEex_2DAGetAtStrings("MXSPLBON", tostring(iLevel), tostring(IEex_GetActorStat(summonerID, ex_caster_type_spell_slots[iCasterType][2]))))
					if iCasterType == 3 then
						newSpellSlots[8][iLevel] = 1
					end
				end
				newSpellSlots[iCasterType][iLevel] = numSlots
			end
		end
	end
	local summonerSpells = IEex_FetchSpellInfo(summonerID, casterTypes)
	for cType, levelList in pairs(summonerSpells) do
		for i = 1, 9, 1 do
			if #levelList >= i then
				local numSlots = 0
				if newSpellSlots[cType] ~= nil and newSpellSlots[cType][i] ~= nil then
					numSlots = newSpellSlots[cType][i]
				end
				local levelI = levelList[i]
				local maxCastable = levelI[1]
				local sorcererCastableCount = levelI[2]
				local levelISpells = levelI[3]
				if levelISpells ~= nil and #levelISpells > 0 then
					if cType == 1 or cType == 6 then
						if numSlots > sorcererCastableCount then
							numSlots = sorcererCastableCount
						end
						if numSlots > 0 then
							IEex_AlterSpellInfo(targetID, cType, i, "", numSlots, numSlots)
							for i2, spell in ipairs(levelISpells) do
								IEex_AlterSpellInfo(targetID, cType, i, spell["resref"], numSlots, numSlots)
							end
							IEex_AlterSpellInfo(targetID, cType, i, "", numSlots, numSlots)
						end
					elseif cType <= 8 then
						if numSlots > 0 then
							for i2, spell in ipairs(levelISpells) do
								local castableCount = spell["castableCount"]
								if castableCount > numSlots then
									castableCount = numSlots
								end
								if castableCount > 0 then
									IEex_AlterSpellInfo(targetID, cType, i, spell["resref"], castableCount, castableCount)
									numSlots = numSlots - castableCount
								end
							end
						end
					end
				end
			end
		end
	end
	if summonerSpells[9] ~= nil and summonerSpells[9][1] ~= nil then
		local levelISpells = summonerSpells[9][1]
		for i2, spell in ipairs(levelISpells) do
			local castableCount = spell["castableCount"]
			if castableCount > 0 then
				IEex_AlterSpellInfo(targetID, 9, 1, spell["resref"], spell["memorizedCount"], castableCount)
			end
		end
	end
--]]
	if newHP > 10 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 18,
["target"] = 2,
["timing"] = 1,
["parameter1"] = newHP - 10,
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 1,
["parameter1"] = IEex_ReadDword(summonerData + 0x5C4),
["parameter2"] = 2,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter1"] = IEex_ReadDword(summonerData + 0x5C4),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["parameter1"] = buttonIndex,
["parameter2"] = 222,
["savingthrow"] = 0x8500000,
["resource"] = "USWI862E",
["source_id"] = targetID
})
	for buttonIndex = 0, 8, 1 do
		local buttonType = IEex_ReadDword(summonerData + 0x3D14 + buttonIndex * 0x4)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["parameter1"] = buttonIndex,
["parameter2"] = buttonType,
["resource"] = "EXBUTTON",
["source_id"] = targetID
})
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 3,
["duration"] = 1,
["parameter1"] = summonerID,
["resource"] = "MESIMUL2",
["source_target"] = targetID,
["source_id"] = targetID
})
end

function MEPROJIM(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
	local teleportX = IEex_ReadDword(effectData + 0x84)
	local teleportY = IEex_ReadDword(effectData + 0x88)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - time_applied) / 15)
	end
	local creatureRES = IEex_ReadLString(effectData + 0x18, 8)
	if creatureRES == "" then
		creatureRES = "USPROJIM"
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["target_x"] = teleportX,
["target_y"] = teleportY,
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 410,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter1"] = 1,
["parameter2"] = 0,
["savingthrow"] = 0x10000,
["resource"] = creatureRES,
["target_x"] = targetX,
["target_y"] = targetY,
["source_id"] = targetID
})
end

function MEPROJI2(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local summonerID = IEex_GetActorSummonerID(targetID)
	local summonerData = IEex_GetActorShare(summonerID)
	if not IEex_IsSprite(summonerID, false) then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 6,
["duration"] = IEex_GetGameTick() + 1,
["resource"] = "MEPROJI2",
["source_target"] = targetID,
["source_id"] = targetID
})

		return
	end
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	extraFlags = bit.bor(extraFlags, 0x40000)
	IEex_WriteDword(creatureData + 0x740, extraFlags)
	IEex_WriteWord(creatureData + 0x5C2, IEex_ReadSignedWord(summonerData + 0x5C2, 0x0))
	IEex_WriteWord(creatureData + 0x924, IEex_ReadSignedWord(summonerData + 0x924, 0x0))
	local newLevelTotal = 0
	for iClass = 1, 11, 1 do
		local newLevel = IEex_ReadByte(summonerData + 0x626 + iClass, 0x0)
		newLevelTotal = newLevelTotal + newLevel
		IEex_WriteByte(creatureData + 0x626 + iClass, newLevel)
--[[
		local iCasterType = IEex_CasterClassToType[iClass]
		if newLevel > 0 and iCasterType ~= nil then
			table.insert(casterTypes, IEex_CasterClassToType[iClass])
			newCasterLevels[iCasterType] = newLevel
			if iClass == 3 then
				table.insert(casterTypes, 8)
				newCasterLevels[8] = newLevel
			end
		end
--]]
	end
	IEex_WriteByte(creatureData + 0x626, newLevelTotal)
	for k, offset in ipairs(ex_simulacrum_copied_fields) do
		if offset[3] == 1 then
			for i = offset[1], offset[2], 1 do
				IEex_WriteByte(creatureData + i, IEex_ReadSignedByte(summonerData + i, 0x0))
			end
		elseif offset[3] == 2 then
			for i = offset[1], offset[2], 2 do
				IEex_WriteWord(creatureData + i, IEex_ReadSignedWord(summonerData + i, 0x0))
			end
		elseif offset[3] == 4 then
			for i = offset[1], offset[2], 4 do
				IEex_WriteDword(creatureData + i, IEex_ReadDword(summonerData + i))
			end
		else
			for i = offset[1], offset[2], offset[3] do
				IEex_WriteLString(creatureData + i, IEex_ReadLString(summonerData + i, offset[3]), offset[3])
			end
		end
	end
	for i = 0, 50, 1 do
		if (i <= 8 or i >= 42) and i ~= 5 then
			local currentSlotRES = IEex_GetItemSlotRES(summonerID, i)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = i,
["resource"] = currentSlotRES,
["source_id"] = targetID
})
		end
	end
	local imageDuration = -1
	IEex_IterateActorEffects(summonerID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local thetiming = IEex_ReadDword(eData + 0x24)
		local theduration = IEex_ReadDword(eData + 0x28)
		local thetime_applied = IEex_ReadDword(eData + 0x6C)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		if theopcode == 502 and theresource == "MEPROJIS" then
			IEex_WriteDword(eData + 0x68, IEex_ReadDword(creatureData + 0x700))
			IEex_WriteDword(eData + 0x110, targetID)
			if thetiming == 4096 then
				imageDuration = math.floor((theduration - thetime_applied) / 15)
			end
		end
		if thetiming == 9 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = IEex_ReadDword(eData + 0x10),
["target"] = IEex_ReadDword(eData + 0x14),
["power"] = IEex_ReadDword(eData + 0x18),
["parameter1"] = IEex_ReadDword(eData + 0x1C),
["parameter2"] = IEex_ReadDword(eData + 0x20),
["timing"] = IEex_ReadDword(eData + 0x24),
["duration"] = IEex_ReadDword(eData + 0x28),
["resource"] = IEex_ReadLString(eData + 0x30, 8),
["dicenumber"] = IEex_ReadDword(eData + 0x38),
["dicesize"] = IEex_ReadDword(eData + 0x3C),
["savingthrow"] = IEex_ReadDword(eData + 0x40),
["savebonus"] = IEex_ReadDword(eData + 0x44),
["special"] = IEex_ReadDword(eData + 0x48),
["school"] = IEex_ReadDword(eData + 0x4C),
["parameter3"] = IEex_ReadDword(eData + 0x60),
["parameter4"] = IEex_ReadDword(eData + 0x64),
["parameter5"] = IEex_ReadDword(eData + 0x68),
["time_applied"] = IEex_ReadDword(eData + 0x6C),
["vvcresource"] = IEex_ReadLString(eData + 0x70, 8),
["resource2"] = IEex_ReadLString(eData + 0x78, 8),
["source_x"] = IEex_ReadDword(eData + 0x80),
["source_y"] = IEex_ReadDword(eData + 0x84),
["target_x"] = IEex_ReadDword(eData + 0x88),
["target_y"] = IEex_ReadDword(eData + 0x8C),
["restype"] = IEex_ReadDword(eData + 0x90),
["parent_resource"] = IEex_ReadLString(eData + 0x94, 8),
["resource_flags"] = bit.band(IEex_ReadDword(eData + 0x9C), 0xFFFFF9FF),
["impact_projectile"] = IEex_ReadDword(eData + 0xA0),
["sourceslot"] = IEex_ReadDword(eData + 0xA4),
["effvar"] = IEex_ReadLString(eData + 0xA8, 32),
["casterlvl"] = IEex_ReadDword(eData + 0xC8),
["internal_flags"] = IEex_ReadDword(eData + 0xD8),
["sectype"] = IEex_ReadDword(eData + 0xD8),
["source_id"] = IEex_ReadDword(eData + 0x110),
})
		end
	end)
--[[
	if newHP > 10 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 18,
["target"] = 2,
["timing"] = 1,
["parameter1"] = newHP - 10,
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
	end
--]]
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 17,
["target"] = 2,
["timing"] = 1,
["parameter1"] = IEex_ReadSignedWord(summonerData + 0x5C0, 0x0) - (IEex_ReadByte(summonerData + 0x626, 0x0) * math.floor((IEex_ReadSignedWord(summonerData + 0x97C, 0x0) - 10) / 2)),
["parameter2"] = 1,
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 1,
["parameter1"] = IEex_ReadDword(summonerData + 0x5C4),
["parameter2"] = 2,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 53,
["target"] = 2,
["timing"] = 0,
["duration"] = 1,
["parameter1"] = IEex_ReadDword(summonerData + 0x5C4),
["parameter2"] = 0,
["parent_resource"] = "USPOLYMO",
["source_id"] = targetID
})
end

function MEPROJIE(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	if not IEex_IsSprite(IEex_ReadDword(effectData + 0x10C), false) then return end
	local time_applied = IEex_ReadDword(effectData + 0x68)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local bodyFoundPreviously = (IEex_ReadDword(effectData + 0x5C) > 0)
	local areaData = IEex_ReadDword(creatureData + 0x12)
	if areaData > 0 then
		local bodyFound = false
		local ids = IEex_GetIDArea(sourceID, 0x31)
		for k, currentID in ipairs(ids) do
			local currentShare = IEex_GetActorShare(currentID)
			if currentShare > 0 then
				if IEex_ReadLString(currentShare + 0x554, 32) == "USPROJIM" and IEex_GetActorSummonerID(currentID) == sourceID then
					bodyFound = true
					IEex_WriteWord(effectData + 0x44, IEex_ReadSignedWord(currentShare + 0x5C0, 0x0))
					IEex_WriteByte(effectData + 0x46, IEex_ReadByte(currentShare + 0x537E, 0x0))
					IEex_WriteDword(effectData + 0x5C, IEex_ReadDword(currentShare + 0x6))
					IEex_WriteDword(effectData + 0x60, IEex_ReadDword(currentShare + 0xA))
					IEex_WriteLString(effectData + 0x6C, IEex_ReadLString(areaData, 8), 8)
				end
			end
		end
		if not bodyFound and bodyFoundPreviously then
			IEex_WriteDword(effectData + 0x110, 1)
			IEex_WriteWord(creatureData + 0x5C0, IEex_ReadSignedWord(effectData + 0x44, 0x0))
			if IEex_ReadLString(areaData, 8) == IEex_ReadLString(effectData + 0x6C, 8) then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["target_x"] = IEex_ReadDword(effectData + 0x5C),
["target_y"] = IEex_ReadDword(effectData + 0x60),
["source_id"] = sourceID
})
			end
			IEex_IterateActorEffects(targetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local thetiming = IEex_ReadDword(eData + 0x24)
				local thetime_applied = IEex_ReadDword(eData + 0x6C)
				if thetime_applied > time_applied and thetiming ~= 9 then
					IEex_WriteDword(eData + 0x114, 1)
				end
			end)
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = IEex_ReadByte(effectData + 0x46, 0x0),
["resource"] = "MEFACE",
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = parent_resource,
["internal_flags"] = 0x4000000,
["source_id"] = sourceID
})
		end
	end

end

function MEPROJCS(originatingEffectData, effectData, creatureData)
	if creatureData == 0 then return end
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if (opcode == 13 or opcode == 420) and bit.band(internalFlags, 0x4000000) == 0 then
		parameter1 = 1
		IEex_WriteDword(effectData + 0x18, parameter1)
		local targetX = IEex_ReadDword(creatureData + 0x6)
		local targetY = IEex_ReadDword(creatureData + 0xA)
		local summonerID = IEex_GetActorSummonerID(targetID)
		local summonerData = IEex_GetActorShare(summonerID)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["target_x"] = 0,
["target_y"] = 0,
["source_id"] = targetID
})
		if IEex_ReadDword(creatureData + 0x12) == IEex_ReadDword(summonerData + 0x12) then
			IEex_ApplyEffectToActor(summonerID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["target_x"] = targetX,
["target_y"] = targetY,
["source_id"] = summonerID
})
		end
		IEex_ApplyEffectToActor(summonerID, {
["opcode"] = 13,
["target"] = 2,
["timing"] = 1,
["parameter1"] = parameter1,
["parameter2"] = parameter2,
["parent_resource"] = "",
["internal_flags"] = 0x4000000,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 168,
["target"] = 2,
["timing"] = 1,
["target_x"] = 0,
["target_y"] = 0,
["source_id"] = targetID
})
		return true
--[[
	elseif opcode == 68 then
		local targetX = IEex_ReadDword(creatureData + 0x6)
		local targetY = IEex_ReadDword(creatureData + 0xA)
		local summonerID = IEex_GetActorSummonerID(targetID)
		local summonerData = IEex_GetActorShare(summonerID)
		local theparent_resource = ""
		IEex_IterateActorEffects(summonerID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			if theopcode == 502 and theresource == "MEPROJIS" then
				theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			end
		end)
		if theparent_resource ~= "" then
			IEex_ApplyEffectToActor(summonerID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = theparent_resource,
["source_id"] = summonerID
})
		end
		return true
--]]
	end
	return false
end

function MEPROJIS(originatingEffectData, effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_ReadDword(originatingEffectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	if sourceID == targetID or not IEex_IsSprite(sourceID, false) then return end
	local sourceData = IEex_GetActorShare(sourceID)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local resource = IEex_ReadLString(effectData + 0x2C, 8)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local o_parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
	local o_resist_dispel = IEex_ReadDword(originatingEffectData + 0x58)
	local o_time_applied = IEex_ReadDword(originatingEffectData + 0x68)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if (opcode == 13 and bit.band(internalFlags, 0x4000000) == 0) or (opcode == 254 and resource == o_parent_resource and bit.band(internalFlags, 0x4000000) == 0) or (opcode == 58 and (o_resist_dispel == 1 or o_resist_dispel == 3)) or opcode == 420 or opcode == 428 then
		if opcode == 13 then
			parameter1 = 1
			IEex_WriteDword(effectData + 0x18, parameter1)
		end
		local targetX = IEex_ReadDword(sourceData + 0x6)
		local targetY = IEex_ReadDword(sourceData + 0xA)
		IEex_WriteWord(creatureData + 0x5C0, IEex_ReadSignedWord(sourceData + 0x5C0, 0x0))
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["target_x"] = 0,
["target_y"] = 0,
["source_id"] = sourceID
})
		if IEex_ReadDword(creatureData + 0x12) == IEex_ReadDword(sourceData + 0x12) then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["target_x"] = targetX,
["target_y"] = targetY,
["source_id"] = targetID
})
		end
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 168,
["target"] = 2,
["timing"] = 1,
["target_x"] = 0,
["target_y"] = 0,
["source_id"] = sourceID
})
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local thetiming = IEex_ReadDword(eData + 0x24)
			local thetime_applied = IEex_ReadDword(eData + 0x6C)
			if thetime_applied > o_time_applied and thetiming ~= 9 then
				IEex_WriteDword(eData + 0x114, 1)
			end
		end)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = o_parent_resource,
["internal_flags"] = 0x4000000,
["source_id"] = targetID
})
		return true
	end
	return false
end

ex_mending_items = {["00MISC18"] = {"00SWDS02", "00SWDL02", "00SWDC94", "00SWDB02", "00SWDT02", }, ["00MISC19"] = {"00SHLD01", "00SHLD02", "00SHLD03", "00SHLD04", "00SHLD05", "00SHLD06", "00SHLD08", "00SHLD09", "00SHLD10", "00SHLD12", "00SHLD13", "00SHLD14", "00SHLD15", }, ["00MISC20"] = {"00PLAT01", }, ["00MISC21"] = {"00AMUL05", "00AMUL10", "00AMUL11", "00AMUL13", "00BELT01", "00FLAL99", "00HELM01", "00HELM02", "00HELM03", "00HELM04", "00HELM05", "00HELM06", "00RING02", "00GENKS", "50MISC38", "51MISC39", "63AMULIX", }, ["00MISC22"] = {"USPLAT15", "USPLAT15", "00PLAT04", }, }

function MEMENDIN(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local numItemsRepaired = 0
	for i = 0, 50, 1 do
		local slotData = IEex_ReadDword(creatureData + 0x4AD8 + i * 0x4)
		if slotData > 0 then
			local itemRES = IEex_ReadLString(slotData + 0xC, 8)
			if ex_mending_items[itemRES] ~= nil and (parameter1 == -1 or numItemsRepaired < parameter1) then
				numItemsRepaired = numItemsRepaired + 1
				local newItemRES = ex_mending_items[itemRES][math.random(#ex_mending_items[itemRES])]
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = i,
["resource"] = newItemRES,
["source_id"] = sourceID
})
			end
		end
	end
end

function MEERUPT(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local sourceID = IEex_GetActorIDShare(creatureData)
	if sourceID <= 0 then return end
	local summonerID = IEex_GetActorSummonerID(sourceID)
--	IEex_WriteWord(creatureData + 0x730, 0)
	local summonerData = IEex_GetActorShare(summonerID)
	if summonerData <= 0 then return end
	local summonerX, summonerY = IEex_GetActorLocation(summonerID)
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = 30,
["resource"] = "METELEFI",
["source_x"] = summonerX,
["source_y"] = summonerY,
["target_x"] = summonerX,
["target_y"] = summonerY,
["source_id"] = sourceID
})
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 0,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["source_x"] = summonerX,
["source_y"] = summonerY,
["target_x"] = summonerX,
["target_y"] = summonerY,
["source_id"] = sourceID
})
end

function MEERUPT2(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local sourceData = IEex_GetActorShare(sourceID)
	if sourceData <= 0 then return end
	local summonerID = IEex_GetActorSummonerID(sourceID)
--	IEex_WriteWord(creatureData + 0x730, 0)
	local summonerData = IEex_GetActorShare(summonerID)
	if summonerData <= 0 then return end
	local summonerX, summonerY = IEex_GetActorLocation(summonerID)
	local creatureName = IEex_ReadLString(sourceData + 0x598, 8)
	local casterlvl = 1
	IEex_IterateActorEffects(summonerID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		if theopcode == 0 and theresource == creatureName then
			casterlvl = IEex_ReadDword(eData + 0xC8)
		end
	end)
--[[
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 430,
["target"] = 2,
["timing"] = 0,
["parameter2"] = 37,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["source_x"] = IEex_ReadDword(effectData + 0x84),
["source_y"] = IEex_ReadDword(effectData + 0x88),
["target_x"] = IEex_ReadDword(effectData + 0x84),
["target_y"] = IEex_ReadDword(effectData + 0x88),
["casterlvl"] = casterlvl,
["source_id"] = summonerID
})
--]]
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 430,
["target"] = 2,
["timing"] = 0,
["parameter2"] = 334,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["source_x"] = IEex_ReadDword(effectData + 0x84),
["source_y"] = IEex_ReadDword(effectData + 0x88),
["target_x"] = IEex_ReadDword(effectData + 0x84),
["target_y"] = IEex_ReadDword(effectData + 0x88),
["casterlvl"] = casterlvl,
["source_id"] = targetID
})
--[[
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 6,
["duration"] = IEex_GetGameTick() + 1,
["resource"] = "MEERUPT3",
["source_x"] = IEex_ReadDword(effectData + 0x84),
["source_y"] = IEex_ReadDword(effectData + 0x88),
["target_x"] = IEex_ReadDword(effectData + 0x84),
["target_y"] = IEex_ReadDword(effectData + 0x88),
["source_id"] = targetID
})
--]]
end

function MEERUPT3(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local sourceData = IEex_GetActorShare(sourceID)
	if sourceData <= 0 then return end
	local summonerID = IEex_GetActorSummonerID(sourceID)
	local summonerData = IEex_GetActorShare(summonerID)
	if summonerData <= 0 then return end
	local summonerX, summonerY = IEex_GetActorLocation(summonerID)
	local found_it = false
	IEex_IterateIDs(IEex_ReadDword(summonerData + 0x12), 0, function(id)
		local projectileData = IEex_GetActorShare(id)
		if found_it == false and IEex_ReadWord(projectileData + 0x6E, 0x0) == 37 and IEex_ReadDword(projectileData + 0x72) == summonerID and IEex_ReadDword(projectileData + 0x76) == targetID then
			found_it = true
--			IEex_Search(IEex_ReadDword(projectileData + 0x6), IEex_ReadDword(projectileData + 0x192), 0x300, false)
--			IEex_Search(IEex_ReadDword(projectileData + 0xA), IEex_ReadDword(projectileData + 0x192), 0x300, false)
			IEex_WriteDword(projectileData + 0x6, IEex_ReadDword(creatureData + 0x6))
			IEex_WriteDword(projectileData + 0xA, IEex_ReadDword(creatureData + 0xA))
			IEex_WriteWord(projectileData + 0x70, 100)
		end
	end)
end

--[[
function MEERUPT3(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local sourceData = IEex_GetActorShare(sourceID)
	if sourceData <= 0 then return end
	local found_it = false
	IEex_IterateIDs(IEex_ReadDword(creatureData + 0x12), 0, function(id)
		local projectileData = IEex_GetActorShare(id)
		if found_it == false and IEex_ReadWord(projectileData + 0x6E, 0x0) == 37 and IEex_ReadDword(projectileData + 0x72) == sourceID then
			found_it = true
			local projectileTargetData = IEex_GetActorShare(IEex_ReadDword(projectileData + 0x76))
			if projectileTargetData > 0 then
				IEex_WriteDword(projectileData + 0x6, IEex_ReadDword(projectileTargetData + 0x6))
				IEex_WriteDword(projectileData + 0xA, IEex_ReadDword(projectileTargetData + 0xA))
			end
		end
	end)
end
--]]
function MESUMCAS(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local sourceData = IEex_GetActorShare(sourceID)
	if sourceData <= 0 then return end
	local summonerID = IEex_GetActorSummonerID(sourceID)
--	IEex_WriteWord(creatureData + 0x730, 0)
	local summonerData = IEex_GetActorShare(summonerID)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	internalFlags = bit.bor(internalFlags, IEex_ReadDword(sourceData + 0x734))
	local casterLevel = IEex_ReadSignedByte(sourceData + 0x730, 0x0)
	if casterLevel == -1 then
		casterLevel = 1
	end
	local casterClass = IEex_ReadSignedByte(sourceData + 0x731, 0x0)
	if casterClass == -1 then
		casterClass = 0
	end
	local casterDomain = IEex_ReadSignedByte(sourceData + 0x732, 0x0)
	if casterDomain == -1 then
		casterDomain = 0
	end
--[[
	if summonerData <= 0 then
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			local thespecial = IEex_ReadDword(eData + 0x48)
			if theopcode == 500 and theresource == "MESUCREA" then
				summonerID = IEex_Helper_GetBridge("IEex_ConstantID", IEex_ReadDword(eData + 0x68))
--				summonerID = IEex_ReadDword(eData + 0x110)
				casterLevel = IEex_ReadByte(eData + 0xC8, 0x0)
				casterClass = IEex_ReadByte(eData + 0xC9, 0x0)
				casterDomain = IEex_ReadByte(eData + 0xCA, 0x0)
			end
		end)
		summonerData = IEex_GetActorShare(summonerID)
		if summonerData <= 0 then return end
	end
--]]
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if bit.band(savingthrow, 0x100000) > 0 then
		targetID = summonerID
	end
	local summonerX, summonerY = IEex_GetActorLocation(summonerID)

	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["internal_flags"] = internalFlags,
["casterlvl"] = casterLevel + casterClass * 0x100 + casterDomain * 0x10000,
["source_x"] = summonerX,
["source_y"] = summonerY,
["target_x"] = IEex_ReadDword(effectData + 0x84),
["target_y"] = IEex_ReadDword(effectData + 0x88),
["source_id"] = summonerID
})

end

me_past_seconds = {}
me_past_seconds_count = 18
me_past_effects = {}
function METIMELG(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 0x1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local time_applied = IEex_ReadDword(effectData + 0x24)
	local me_current_effects = {}
	IEex_IterateActorEffects(targetID, function(eData)
		local the_opcode = IEex_ReadDword(eData + 0x10)
		local the_timing = IEex_ReadDword(eData + 0x24)
		local the_duration = IEex_ReadDword(eData + 0x28)
		local the_internal_flags = IEex_ReadDword(eData + 0xD8)
--[[
		if IEex_ReadLString(eData + 0x94, 8) == "SPPR406" then
			Infinity_DisplayString("the_duration: " .. the_duration .. ", time_applied: " .. time_applied)
		end
--]]
		if the_timing ~= 1 and the_timing ~= 2 and the_timing ~= 9 and the_opcode ~= 124 and the_opcode ~= 500 and ((the_duration - time_applied < 15 and bit.band(the_internal_flags, 0x8000000) == 0) or the_opcode == 119 or the_opcode == 218) then
			IEex_WriteDword(eData + 0xD8, bit.bor(the_internal_flags, 0x8000000))
			table.insert(me_current_effects, {
["opcode"] = IEex_ReadDword(eData + 0x10),
["target"] = IEex_ReadDword(eData + 0x14),
["power"] = IEex_ReadDword(eData + 0x18),
["parameter1"] = IEex_ReadDword(eData + 0x1C),
["parameter2"] = IEex_ReadDword(eData + 0x20),
["timing"] = IEex_ReadDword(eData + 0x24),
["duration"] = IEex_ReadDword(eData + 0x28),
["resource"] = IEex_ReadLString(eData + 0x30, 8),
["dicenumber"] = IEex_ReadDword(eData + 0x38),
["dicesize"] = IEex_ReadDword(eData + 0x3C),
["savingthrow"] = IEex_ReadDword(eData + 0x40),
["savebonus"] = IEex_ReadDword(eData + 0x44),
["special"] = IEex_ReadDword(eData + 0x48),
["school"] = IEex_ReadDword(eData + 0x4C),
["sectype"] = IEex_ReadDword(eData + 0x50),
["parameter3"] = IEex_ReadDword(eData + 0x60),
["parameter4"] = IEex_ReadDword(eData + 0x64),
["parameter5"] = IEex_ReadDword(eData + 0x68),
["time_applied"] = IEex_ReadDword(eData + 0x6C),
["vvcresource"] = IEex_ReadLString(eData + 0x70, 8),
["resource2"] = IEex_ReadLString(eData + 0x78, 8),
["source_x"] = IEex_ReadDword(eData + 0x80),
["source_y"] = IEex_ReadDword(eData + 0x84),
["target_x"] = IEex_ReadDword(eData + 0x88),
["target_y"] = IEex_ReadDword(eData + 0x8C),
["restype"] = IEex_ReadDword(eData + 0x90),
["parent_resource"] = IEex_ReadLString(eData + 0x94, 8),
["resource_flags"] = bit.band(IEex_ReadDword(eData + 0x9C), 0xFFFFF9FF),
["impact_projectile"] = IEex_ReadDword(eData + 0xA0),
["sourceslot"] = IEex_ReadDword(eData + 0xA4),
["effvar"] = IEex_ReadLString(eData + 0xA8, 32),
["casterlvl"] = IEex_ReadDword(eData + 0xC8),
["effect_identifier"] = IEex_ReadDword(eData + 0xD4),
["internal_flags"] = the_internal_flags,
["source_id"] = IEex_ReadDword(eData + 0x110),
})
		end
	end)
	if me_past_seconds["" .. targetID] == nil or (me_past_seconds["" .. targetID][1][6] ~= nil and me_past_seconds["" .. targetID][1][6] > time_applied) then
--		me_past_seconds["" .. targetID] = {{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}}
		me_past_seconds["" .. targetID] = {{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}}	
	end
	for i = me_past_seconds_count, 2, -1 do
		me_past_seconds["" .. targetID][i] = me_past_seconds["" .. targetID][i - 1]
	end
--[[
	Infinity_DisplayString(#me_current_effects)
	if #me_current_effects > 0 then
		Infinity_DisplayString(me_current_effects[1]["parent_resource"])
	end
--]]
	local areaRES = ""
	if IEex_ReadDword(creatureData + 0x12) > 0 then
		areaRES = IEex_ReadLString(IEex_ReadDword(creatureData + 0x12), 8)
	end
	
	me_past_seconds["" .. targetID][1] = {IEex_ReadSignedWord(creatureData + 0x5C0, 0x0), IEex_ReadDword(creatureData + 0x6), IEex_ReadDword(creatureData + 0xA), areaRES, me_current_effects, time_applied}
end

function MEUGU(actorID)
	local effectID = math.random(0x7FFFFFFF)
	IEex_ApplyEffectToActor(actorID, {
["opcode"] = 142,
["target"] = 2,
["timing"] = 0,
["duration"] = 7,
["effect_identifier"] = effectID,
["source_id"] = actorID
})
	IEex_IterateActorEffects(actorID, function(eData)
		local the_effectID = IEex_ReadDword(eData + 0xD4)
		if the_effectID == effectID then
			IEex_WriteDword(eData + 0x28, IEex_ReadDword(eData + 0x6C) + 7)
		end
	end)
end

function METIMETR(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 0x1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local time_applied = IEex_ReadDword(effectData + 0x24)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local previous_second = {}
	local game_tick = IEex_GetGameTick()
	if parameter1 <= 0 then return end
	if parameter1 > me_past_seconds_count then
		parameter1 = me_past_seconds_count
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 1,
["parameter2"] = 224,
["resource"] = "USTIMELG",
["parent_resource"] = "USTIMELS",
["internal_flags"] = 0x18000000,
["source_target"] = targetID,
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55701,
["parent_resource"] = "USTIMELS",
["internal_flags"] = 0x18000000,
["source_target"] = targetID,
["source_id"] = targetID
})
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 9,
["resource"] = "USTIMELS",
["parent_resource"] = "USTIMELS",
["internal_flags"] = 0x18000000,
["source_target"] = targetID,
["source_id"] = targetID
})
--	local current_past_seconds = me_past_seconds
	if me_past_seconds["" .. targetID] == nil then
--		me_past_seconds["" .. targetID] = {{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}}
		me_past_seconds["" .. targetID] = {{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}}
	end
--	me_past_effects["" .. targetID] = {}
	local areaRES = ""
	local areaType = 0x800
	if IEex_ReadDword(creatureData + 0x12) > 0 then
		areaRES = IEex_ReadLString(IEex_ReadDword(creatureData + 0x12), 8)
		areaType = IEex_ReadWord(IEex_ReadDword(creatureData + 0x12) + 0x40, 0x0)
	end
	local currentHP = IEex_ReadSignedWord(creatureData + 0x5C0, 0x0)
	local currentX = IEex_ReadDword(creatureData + 0x6)
	local currentY = IEex_ReadDword(creatureData + 0xA)
	local seconds_ago = 0
	local the_effect = {}
	local effect_opcode = 0
	local effect_duration = 0
	local effect_timing = 0
	for i = 1, parameter1, 1 do
		if #me_past_seconds["" .. targetID][i] > 0 then
			seconds_ago = seconds_ago + 1
		end
	end
	if seconds_ago > 0 then

		IEex_IterateActorEffects(targetID, function(eData)
			local the_opcode = IEex_ReadDword(eData + 0x10)
			local the_timing = IEex_ReadDword(eData + 0x24)
			local the_parent_resource = IEex_ReadLString(eData + 0x94, 8)
			local the_internal_flags = IEex_ReadDword(eData + 0xD8)
			local the_time_applied = IEex_ReadDword(eData + 0x6C)
			if the_time_applied < time_applied and the_timing ~= 1 and the_timing ~= 2 and the_timing ~= 9 and the_parent_resource ~= parent_resource and the_opcode ~= 500 and bit.band(the_internal_flags, 0x10000000) == 0 then
				local the_duration = IEex_ReadDword(eData + 0x28)
				the_duration = the_duration + (seconds_ago * 15)
				the_time_applied = the_time_applied + (seconds_ago * 15)
				IEex_WriteDword(eData + 0x28, the_duration)
				IEex_WriteDword(eData + 0x6C, the_time_applied)
				if the_time_applied >= time_applied then
					IEex_WriteDword(eData + 0x28, 0)
					IEex_WriteDword(eData + 0x114, 1)
				end
			end
		end)

	end
	for i = 1, parameter1, 1 do
		previous_second = me_past_seconds["" .. targetID][1]
		for j = 1, me_past_seconds_count - 1, 1 do
			me_past_seconds["" .. targetID][j] = me_past_seconds["" .. targetID][j + 1]
		end
		me_past_seconds["" .. targetID][me_past_seconds_count] = {}
--		me_past_effects["" .. targetID]["" .. i] = previous_second[5]
		if #previous_second > 0 then
--			Infinity_DisplayString(i .. " second(s) before: " .. previous_second[1] .. " HP, [" .. previous_second[2] .. "." .. previous_second[3] .. "], " .. previous_second[4]) 
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 17,
["target"] = 2,
["timing"] = 6,
["duration"] = game_tick + i,
["parameter1"] = previous_second[1],
["parameter2"] = 1,
["parent_resource"] = parent_resource,
["internal_flags"] = 0x18000000,
["source_target"] = targetID,
["source_id"] = targetID
})
			currentHP = previous_second[1]
			if bit.band(areaType, 0x800) == 0 and areaRES ~= "" and areaRES == previous_second[4] then
--[[
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["duration"] = game_tick + i,
["parent_resource"] = parent_resource,
["source_x"] = currentX,
["source_y"] = currentY,
["target_x"] = previous_second[2],
["target_y"] = previous_second[3],
["internal_flags"] = 0x18000000,
["source_target"] = targetID,
["source_id"] = targetID
})
--]]
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 6,
["duration"] = game_tick + i,
["resource"] = "USINTELE",
["parent_resource"] = parent_resource,
["source_x"] = currentX,
["source_y"] = currentY,
["target_x"] = previous_second[2],
["target_y"] = previous_second[3],
["internal_flags"] = 0x18000000,
["source_target"] = targetID,
["source_id"] = targetID
})
--				currentX = previous_second[2]
--				currentY = previous_second[3]
			end
			for j = 1, #previous_second[5], 1 do
				the_effect = previous_second[5][j]
				effect_opcode = the_effect["opcode"]
				effect_timing = the_effect["timing"]
				effect_duration = the_effect["duration"]
				if the_effect["time_applied"] + seconds_ago * 15 < time_applied and (effect_duration < time_applied or (effect_opcode == 218 and the_effect["parameter1"] > 0 and not IEex_GetActorSpellState(targetID, 18) and not IEex_GetActorSpellState(targetID, 19)) or (effect_opcode == 119 and the_effect["parameter1"] > 0 and not IEex_GetActorSpellState(targetID, 63) and not IEex_GetActorSpellState(targetID, 66))) then
					
					if effect_timing == 4096 then
						effect_timing = 0
					elseif effect_timing == 6 then
						effect_timing = 3
					elseif effect_timing == 7 then
						effect_timing = 4
					end		
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = the_effect["opcode"],
["target"] = the_effect["target"],
["power"] = the_effect["power"],
["parameter1"] = the_effect["parameter1"],
["parameter2"] = the_effect["parameter2"],
["timing"] = effect_timing,
["duration"] = 0x10000000,
["time_applied"] = the_effect["time_applied"] + seconds_ago * 15,
["resource"] = the_effect["resource"],
["dicenumber"] = the_effect["dicenumber"],
["dicesize"] = the_effect["dicesize"],
["savingthrow"] = the_effect["savingthrow"],
["savebonus"] = the_effect["savebonus"],
["special"] = the_effect["special"],
["school"] = the_effect["school"],
["parameter3"] = the_effect["parameter3"],
["parameter4"] = the_effect["parameter4"],
["parameter5"] = the_effect["parameter5"],
["vvcresource"] = the_effect["vvcresource"],
["resource2"] = the_effect["resource2"],
["source_x"] = the_effect["source_x"],
["source_y"] = the_effect["source_y"],
["target_x"] = the_effect["target_x"],
["target_y"] = the_effect["target_y"],
["restype"] = the_effect["restype"],
["parent_resource"] = the_effect["parent_resource"],
["resource_flags"] = the_effect["resource_flags"],
["impact_projectile"] = the_effect["impact_projectile"],
["sourceslot"] = the_effect["sourceslot"],
["effvar"] = the_effect["effvar"],
["casterlvl"] = the_effect["casterlvl"],
["internal_flags"] = bit.bor(the_effect["internal_flags"], 0x8000000),
["effect_identifier"] = the_effect["effect_identifier"],
["sectype"] = the_effect["sectype"],
["source_id"] = the_effect["source_id"],
})
					IEex_IterateActorEffects(targetID, function(eData)
						local the_effectID = IEex_ReadDword(eData + 0xD4)
						if the_effectID == the_effect["effect_identifier"] then
							IEex_WriteDword(eData + 0x28, the_effect["duration"] + (seconds_ago * 15))
						end
					end)
					if effect_opcode == 119 then
						IEex_IterateActorEffects(targetID, function(eData)
							local the_opcode = IEex_ReadDword(eData + 0x10)
							if the_opcode == effect_opcode then
								IEex_WriteDword(eData + 0x1C, the_effect["parameter1"])
							end
						end)
					end
				elseif effect_opcode == 119 and the_effect["parameter1"] > 0 then
					IEex_IterateActorEffects(targetID, function(eData)
						local the_opcode = IEex_ReadDword(eData + 0x10)
						if the_opcode == effect_opcode then
							IEex_WriteDword(eData + 0x1C, the_effect["parameter1"])
						end
					end)
				elseif effect_opcode == 218 then
					if the_effect["parameter2"] == 0 and the_effect["parameter3"] > 0 then
						IEex_IterateActorEffects(targetID, function(eData)
							local the_opcode = IEex_ReadDword(eData + 0x10)
							local the_parameter2 = IEex_ReadDword(eData + 0x20)
							if the_opcode == effect_opcode and the_parameter2 == 0 then
								IEex_WriteDword(eData + 0x1C, the_effect["parameter1"])
								IEex_WriteDword(eData + 0x60, the_effect["parameter3"])
							end
						end)
					elseif the_effect["parameter2"] == 1 and the_effect["parameter1"] > 0 then
						IEex_IterateActorEffects(targetID, function(eData)
							local the_opcode = IEex_ReadDword(eData + 0x10)
							local the_parameter2 = IEex_ReadDword(eData + 0x20)
							if the_opcode == effect_opcode and the_parameter2 == 1 then
								IEex_WriteDword(eData + 0x1C, the_effect["parameter1"])
							end
						end)
					end
				end
			end
--[[
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 6,
["duration"] = game_tick + i,
["parameter1"] = i,
["parameter2"] = time_applied,
["special"] = game_tick,
["resource"] = "METIMEEF",
["parent_resource"] = parent_resource,
["source_target"] = targetID,
["source_id"] = targetID
})
--]]
		end
	end
end

function IEex_PreventMovingAttacksOfOpportunity(targetID, extraTicks)
	local tick = IEex_GetGameTick()
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		if theopcode == 500 and theresource == "MEAPRBON" then
			IEex_WriteDword(eData + 0x60, tick + extraTicks)
		end
	end)
end

function MEREANIM(effectData, creatureData)
	local nonliving_race = {["" .. ex_construct_race] = 1, ["" .. ex_fiend_race] = 1, ["108"] = 1, ["115"] = 1, ["120"] = 1, ["152"] = 1, ["156"] = 1, ["164"] = 1, ["167"] = 1, ["175"] = 1, ["178"] = 1, ["190"] = 1, ["192"] = 1, ["201"] = 1, ["202"] = 1, ["203"] = 1, ["204"] = 1, ["205"] = 1, ["206"] = 1, ["207"] = 1, ["208"] = 1, ["209"] = 1, ["210"] = 1, ["211"] = 1, ["212"] = 1, ["213"] = 1, ["214"] = 1, ["215"] = 1, ["255"] = 1, }
	IEex_WriteDword(effectData + 0x110, 0x1)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local sourceData = IEex_GetActorShare(sourceID)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local spellRES = IEex_ReadLString(effectData + 0x18, 8)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local getHighestLevel = (bit.band(savingthrow, 0x100000) > 0)
	local ignoreHigherLevel = (bit.band(savingthrow, 0x200000) > 0)
	local includeNonliving = (bit.band(savingthrow, 0x800000) > 0)
	local recruitTarget = (bit.band(savingthrow, 0x1000000) > 0)
	local maxDistance = IEex_ReadDword(effectData + 0x44)
	local casterlvl = IEex_ReadByte(effectData + 0xC4, 0x0)
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	local areaActorIDList = IEex_GetIDArea(sourceID, 0x31)
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local actorX = 0
	local actorY = 0
	local currentShare = 0
	local currentStates = 0
	local currentDistance = 0
	local shortestDistance = 32767
	local currentLevel = 0
	local highestLevel = 0
	local chosenIDs = {}
	if bit.band(internalFlags, 0x400000) > 0 then
		maxDistance = 200
	end
	if bit.band(internalFlags, 0x40000) > 0 then
		maxDistance = math.floor(maxDistance * 1.5)
	end
	if bit.band(internalFlags, 0x400000) == 0 then
		for k, v in ipairs(areaActorIDList) do
			if IEex_IsSprite(v, true) then
				currentShare = IEex_GetActorShare(v)
				actorX = IEex_ReadDword(currentShare + 0x6)
				actorY = IEex_ReadDword(currentShare + 0xA)
				currentStates = IEex_ReadDword(currentShare + 0x5BC)
				if bit.band(currentStates, 0xE00) > 0 and bit.band(currentStates, 0xC0) == 0 and (IEex_ReadDword(currentShare + 0x5C4) > 1000) and (includeNonliving or (IEex_ReadByte(currentShare + 0x25, 0x0) ~= 4 and nonliving_race["" .. IEex_ReadByte(currentShare + 0x26, 0x0)] == nil)) then
					currentDistance = IEex_GetDistance(targetX, targetY, actorX, actorY)
					currentLevel = IEex_ReadByte(currentShare + 0x626, 0x0)
					if IEex_ReadDword(sourceData + 0x12) == IEex_ReadDword(currentShare + 0x12) and (maxDistance <= 0 or currentDistance <= maxDistance) and (currentDistance < shortestDistance or (getHighestLevel and currentLevel > highestLevel)) and (ignoreHigherLevel == false or currentLevel <= casterlvl + ex_reanimation_level_check_bonus) and (getHighestLevel == false or highestLevel <= currentLevel) then
						shortestDistance = currentDistance
						highestLevel = currentLevel
						chosenIDs[1] = v
					end
				end
			end
		end
	else
		for k, v in ipairs(areaActorIDList) do
			if IEex_IsSprite(v, true) then
				currentShare = IEex_GetActorShare(v)
				actorX = IEex_ReadDword(currentShare + 0x6)
				actorY = IEex_ReadDword(currentShare + 0xA)
				currentStates = IEex_ReadDword(currentShare + 0x5BC)
				if bit.band(currentStates, 0xE00) > 0 and bit.band(currentStates, 0xC0) == 0 and (IEex_ReadDword(currentShare + 0x5C4) > 1000) and (includeNonliving or (IEex_ReadByte(currentShare + 0x25, 0x0) ~= 4 and nonliving_race["" .. IEex_ReadByte(currentShare + 0x26, 0x0)] == nil)) then
					currentDistance = IEex_GetDistance(targetX, targetY, actorX, actorY)
					currentLevel = IEex_ReadByte(currentShare + 0x626, 0x0)
					if IEex_ReadDword(sourceData + 0x12) == IEex_ReadDword(currentShare + 0x12) and (maxDistance <= 0 or currentDistance <= maxDistance) and (ignoreHigherLevel == false or currentLevel <= casterlvl + ex_reanimation_level_check_bonus) then
						table.insert(chosenIDs, v)
					end
				end
			end
		end
	end

	for k, chosenID in ipairs(chosenIDs) do
		currentShare = IEex_GetActorShare(chosenID)
		actorX = IEex_ReadDword(currentShare + 0x6)
		actorY = IEex_ReadDword(currentShare + 0xA)
		IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["resource"] = "MERAISED",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
		currentStates = IEex_ReadDword(currentShare + 0x5BC)
--		IEex_WriteByte(currentShare + 0x24, 2)
		IEex_WriteByte(currentShare + 0x25, 4)
		IEex_WriteByte(currentShare + 0x3E3A, 2)
		IEex_WriteByte(currentShare + 0x3E3B, 4)
		IEex_WriteDword(currentShare + 0x5BC, bit.band(currentStates, 0xFFFFFAFF)) 
		IEex_WriteDword(currentShare + 0x920, bit.band(IEex_ReadDword(currentShare + 0x920), 0xFFFFFAFF)) 
		IEex_WriteWord(currentShare + 0x5C0, 1)
		IEex_WriteLString(currentShare + 0x56DC, "", 8)
		IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 17,
["target"] = 2,
["parameter1"] = 100,
["parameter2"] = 2,
["timing"] = 1,
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
--[[
		IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 72,
["target"] = 2,
["parameter1"] = 5,
["parameter2"] = 1,
["timing"] = 1,
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
--]]
		local reanimatedEA = 5
		local sourceEA = IEex_ReadByte(sourceData + 0x24, 0x0)
		if sourceEA <= 30 then		
--[[
			IEex_WriteLString(currentShare + 0x810, "", 8)
			IEex_WriteLString(currentShare + 0x750, "", 8)
			IEex_WriteLString(currentShare + 0x4FFC, "", 8)
			IEex_WriteLString(currentShare + 0x818, "", 8)
			IEex_WriteLString(currentShare + 0x820, "", 8)
			IEex_WriteLString(currentShare + 0x828, "", 8)
			IEex_WriteLString(currentShare + 0x830, "", 8)
--]]
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 82,
["target"] = 2,
["parameter2"] = 0,
["timing"] = 1,
["resource"] = "MENOBCS",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 82,
["target"] = 2,
["parameter2"] = 1,
["timing"] = 1,
["resource"] = "MENOBCS",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 82,
["target"] = 2,
["parameter2"] = 2,
["timing"] = 1,
["resource"] = "MENOBCS",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 82,
["target"] = 2,
["parameter2"] = 4,
["timing"] = 1,
["resource"] = "MENOBCS",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 82,
["target"] = 2,
["parameter2"] = 5,
["timing"] = 1,
["resource"] = "MENOBCS",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 82,
["target"] = 2,
["parameter2"] = 6,
["timing"] = 1,
["resource"] = "MENOBCS",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 82,
["target"] = 2,
["parameter2"] = 7,
["timing"] = 1,
["resource"] = "MENOBCS",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 72,
["target"] = 2,
["parameter1"] = reanimatedEA,
["parameter2"] = 0,
["timing"] = 9,
["parent_resource"] = "MEREANEA",
["source_target"] = chosenID,
["source_id"] = sourceID
})
--[[
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 412,
["target"] = 2,
["parameter2"] = 1,
["timing"] = 0,
["duration"] = 0x20000000,
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
--]]
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 0,
["parameter2"] = 5,
["resource"] = "EXBUTTON",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 1,
["parameter2"] = 3,
["resource"] = "EXBUTTON",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 2,
["parameter2"] = 72,
["resource"] = "EXBUTTON",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 3,
["parameter2"] = 73,
["resource"] = "EXBUTTON",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 4,
["parameter2"] = 14,
["resource"] = "EXBUTTON",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 5,
["parameter2"] = 80,
["resource"] = "EXBUTTON",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 6,
["parameter2"] = 81,
["resource"] = "EXBUTTON",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 7,
["parameter2"] = 82,
["resource"] = "EXBUTTON",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 8,
["parameter2"] = 10,
["resource"] = "EXBUTTON",
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 138,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 1,
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 53,
["parent_resource"] = parent_resource,
["source_target"] = chosenID,
["source_id"] = sourceID
})
		else
			reanimatedEA = sourceEA
		end
--[[

--]]
		if spellRES ~= "" then
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 9,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["casterlvl"] = casterlvl,
["source_target"] = chosenID,
["source_id"] = sourceID
})
		end
		local containerX = 0
		local containerY = 0
		local closestContainer = 0
		currentDistance = 0
		shortestDistance = 32767
		IEex_IterateIDs(IEex_ReadDword(currentShare + 0x12), 0x11, function(containerID)
			local containerData = IEex_GetActorShare(containerID)
			containerX = IEex_ReadDword(containerData + 0x6)
			containerY = IEex_ReadDword(containerData + 0xA)
			currentDistance = IEex_GetDistance(actorX, actorY, containerX, containerY)
			if currentDistance < 20 and currentDistance < shortestDistance and IEex_ReadWord(containerData + 0x5CA, 0x0) == 4 then
				shortestDistance = currentDistance
				closestContainer = containerData
			end
		end)
		if closestContainer > 0 then
			local inventoryItems = {}
			for i = 1, 51, 1 do
				local invItemInfo = IEex_ReadDword(currentShare + 0x4AD4 + i * 0x4)
				if invItemInfo <= 0 then
					table.insert(inventoryItems, "")
				else
					table.insert(inventoryItems, IEex_ReadLString(invItemInfo + 0xC, 8))
				end
			end
			IEex_IterateCPtrList(closestContainer + 0x5AE, function(containerItemData)
				local itemRES = IEex_ReadLString(containerItemData + 0xC, 8)
				local charges1 = IEex_ReadWord(containerItemData + 0x18, 0x0)
				local charges2 = IEex_ReadWord(containerItemData + 0x1A, 0x0)
				local charges3 = IEex_ReadWord(containerItemData + 0x1C, 0x0)
				local resWrapper = IEex_DemandRes(itemRES, "ITM")
				local itemData = 0
				if resWrapper:isValid() then
					itemData = resWrapper:getData()
				end
				if itemData > 0 then
					local itemSlotChoices = me_item_type_slots[IEex_ReadWord(itemData + 0x1C, 0x0)]
					local chosenItemSlot = -1
					if itemSlotChoices ~= nil then
						
						for sloti, slot in ipairs(itemSlotChoices) do
							if (slot == 43 or slot == 45 or slot == 47 or slot == 49) and chosenItemSlot == -1 and inventoryItems[slot + 1] ~= "" and inventoryItems[slot + 2] == "" and (IEex_ReadByte(currentShare + 0x62E, 0x0) > 0 or bit.band(IEex_ReadDword(currentShare + 0x75C), 0x2) > 0) and IEex_ReadByte(itemData + 0x82, 0x0) == 1 and bit.band(IEex_ReadDword(itemData + 0x18), 0x2) == 0 then
								local rightItemWrapper = resWrapper
								if itemRES ~= inventoryItems[slot + 1] then
									rightItemWrapper = IEex_DemandRes(inventoryItems[slot + 1], "ITM")
									local rightItemData = rightItemWrapper:getData()
									if rightItemWrapper:isValid() and IEex_ReadByte(rightItemData + 0x72, 0x0) == 1 and bit.band(IEex_ReadDword(rightItemData + 0x18), 0x2) == 0 then
										chosenItemSlot = slot + 1
										inventoryItems[slot + 2] = itemRES
									end
									rightItemWrapper:free()
								else
									local rightItemData = itemData
									if IEex_ReadByte(rightItemData + 0x72, 0x0) == 1 and bit.band(IEex_ReadDword(rightItemData + 0x18), 0x2) == 0 then
										chosenItemSlot = slot + 1
										inventoryItems[slot + 2] = itemRES
									end
								end
							elseif chosenItemSlot == -1 and inventoryItems[slot + 1] == "" then
								chosenItemSlot = slot
								inventoryItems[slot + 1] = itemRES
							end
						end
					end
					if chosenItemSlot == -1 then
						itemSlotChoices = {18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41}
						for sloti, slot in ipairs(itemSlotChoices) do
							if chosenItemSlot == -1 and inventoryItems[slot + 1] == "" then
								chosenItemSlot = slot
								inventoryItems[slot + 1] = itemRES
							end
						end
					end
					if chosenItemSlot ~= -1 then
						IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = chosenItemSlot,
["parameter2"] = 2,
["resource"] = itemRES,
["source_target"] = chosenID,
["source_id"] = chosenID
})
						if charges1 > 1 or charges2 > 1 or charges3 > 1 then
							IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = charges1,
["parameter2"] = 1,
["parameter3"] = charges2,
["parameter4"] = charges3,
["special"] = chosenItemSlot,
["savingthrow"] = 0x80000,
["resource"] = "EXCHARGE",
["source_target"] = chosenID,
["source_id"] = chosenID
})
							
						end
						
					end
				end
				resWrapper:free()
			end)
--[[
			IEex_ApplyEffectToActor(chosenID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["resource"] = "MEEQUIPR",
["source_target"] = chosenID,
["source_id"] = chosenID
})
--]]
			IEex_WriteByte(closestContainer + 0x863, 1)
		end
	end
end

function MEEQUIPR(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 0x1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local launcherSlot = 0
	local ammoRES = ""
	local ammoInfo = IEex_ReadDword(creatureData + 0xAAC)
	local ammoData = 0
	if ammoInfo > 0 then
		ammoRES = IEex_ReadLString(ammoInfo + 0x8, 8)
		ammoData = IEex_DemandResData(ammoRES, "ITM")
	end
	for i = 1, 4, 1 do
		local invItemInfo = IEex_ReadDword(creatureData + 0xB08 + i * 4)
		if invItemInfo > 0 then
			local itemRES = IEex_ReadLString(invItemInfo + 0xC, 8)
			local charges1 = IEex_ReadWord(invItemInfo + 0x14, 0x0)
			local resWrapper = IEex_DemandRes(itemRES, "ITM")
			local itemData = 0
			if resWrapper:isValid() then
				itemData = resWrapper:getData()
			end
			if itemData > 0 then
				local itemName = IEex_ReadDword(itemData + 0x8)
				local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
				local itemIcon = IEex_ReadLString(itemData + 0x3A, 8)
				local slotData = creatureData + 0x266C + i * 0x34
				if (itemType == 15 or itemType == 18 or itemType == 27) and IEex_ReadByte(itemData + 0x72, 0x0) == 4 and ammoData > 0 and launcherSlot == 0 then
					launcherSlot = i
					IEex_WriteLString(slotData, IEex_ReadLString(ammoData + 0x3A, 8), 8)
					IEex_WriteDword(slotData + 0x8, IEex_ReadDword(ammoData + 0x8))
					IEex_WriteLString(slotData + 0xC, itemIcon, 8)
					IEex_WriteDword(slotData + 0x14, itemName)
					IEex_WriteWord(slotData + 0x18, IEex_ReadWord(ammoInfo + 0x14, 0x0))
					IEex_WriteWord(slotData + 0x1E, 11)
					IEex_WriteLString(slotData + 0x22, ammoRES, 8)
					IEex_WriteDword(slotData + 0x2C, IEex_ReadDword(ammoData + 0x8))
					slotData = creatureData + 0x3574
					IEex_WriteLString(slotData, IEex_ReadLString(ammoData + 0x3A, 8), 8)
					IEex_WriteDword(slotData + 0x8, IEex_ReadDword(ammoData + 0x8))
					IEex_WriteLString(slotData + 0xC, itemIcon, 8)
					IEex_WriteDword(slotData + 0x14, itemName)
					IEex_WriteWord(slotData + 0x18, IEex_ReadWord(ammoInfo + 0x14, 0x0))
					IEex_WriteWord(slotData + 0x1E, 11)
					IEex_WriteLString(slotData + 0x22, ammoRES, 8)
					IEex_WriteDword(slotData + 0x2C, IEex_ReadDword(ammoData + 0x8))
				else
					IEex_WriteLString(slotData, itemIcon, 8)
					IEex_WriteDword(slotData + 0x8, itemName)
					IEex_WriteLString(slotData + 0xC, "", 8)
					IEex_WriteDword(slotData + 0x14, 0)
					IEex_WriteWord(slotData + 0x18, charges1)
					IEex_WriteWord(slotData + 0x1E, 34 + i)
					IEex_WriteLString(slotData + 0x22, itemRES, 8)
					IEex_WriteDword(slotData + 0x2C, itemName)
					if i == 1 then
						IEex_WriteByte(slotData + 0x30, 0)
						slotData = creatureData + 0x3574
						IEex_WriteLString(slotData, itemIcon, 8)
						IEex_WriteDword(slotData + 0x8, itemName)
						IEex_WriteLString(slotData + 0xC, "", 8)
						IEex_WriteDword(slotData + 0x14, 0)
						IEex_WriteWord(slotData + 0x18, charges1)
						IEex_WriteWord(slotData + 0x1E, 34 + i)
						IEex_WriteLString(slotData + 0x22, itemRES, 8)
						IEex_WriteDword(slotData + 0x2C, itemName)
						IEex_WriteByte(slotData + 0x30, 0)
					end
				end
			end
			resWrapper:free()
		end
	end
	if launcherSlot == 1 then
		IEex_WriteByte(creatureData + 0xB1C, 11)
		IEex_WriteByte(creatureData + 0x3572, 11)
	else
		IEex_WriteByte(creatureData + 0xB1C, 35)
		IEex_WriteByte(creatureData + 0x3572, 35)
	end
	IEex_WriteByte(creatureData + 0x3AC0, 1)
end

me_item_type_slots = {
[0] = {15, 16, 17},
[1] = {0},
[2] = {1},
[3] = {2},
[4] = {3},
[5] = {11, 12, 13},
[6] = {5},
[7] = {6},
[9] = {15, 16, 17},
[10] = {7, 8},
[11] = {15, 16, 17},
[12] = {44, 46, 48, 50},
[13] = {15, 16, 17},
[14] = {11, 12, 13},
[15] = {43, 45, 47, 49},
[16] = {43, 45, 47, 49},
[17] = {43, 45, 47, 49},
[18] = {43, 45, 47, 49},
[19] = {43, 45, 47, 49},
[20] = {43, 45, 47, 49},
[21] = {43, 45, 47, 49},
[22] = {43, 45, 47, 49},
[23] = {43, 45, 47, 49},
[24] = {43, 45, 47, 49},
[25] = {43, 45, 47, 49},
[26] = {43, 45, 47, 49},
[27] = {43, 45, 47, 49},
[28] = {43, 45, 47, 49},
[29] = {43, 45, 47, 49},
[30] = {43, 45, 47, 49},
[31] = {11, 12, 13},
[32] = {4},
[35] = {15, 16, 17},
[41] = {44, 46, 48, 50},
[44] = {43, 45, 47, 49},
[47] = {44, 46, 48, 50},
[49] = {44, 46, 48, 50},
[51] = {15, 16, 17},
[53] = {44, 46, 48, 50},
[57] = {43, 45, 47, 49},
[60] = {1},
[61] = {1},
[62] = {1},
[63] = {1},
[64] = {1},
[65] = {1},
[66] = {1},
[67] = {1},
[68] = {1},
[69] = {43, 45, 47, 49},
[72] = {6},
[73] = {5},
}
function EXCHARGE(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local chargeMod1 = IEex_ReadDword(effectData + 0x18)
	local chargeMod2 = IEex_ReadDword(effectData + 0x5C)
	local chargeMod3 = IEex_ReadDword(effectData + 0x60)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local doNotModifyQuantity = (bit.band(savingthrow, 0x10000) > 0)
	local doNotModifyCharges = (bit.band(savingthrow, 0x20000) > 0)
	local goOverMaximum = (bit.band(savingthrow, 0x40000) > 0)
	if bit.band(savingthrow, 0x80000) == 0 then
		chargeMod2 = chargeMod1
		chargeMod3 = chargeMod1
	end
	local special = IEex_ReadDword(effectData + 0x44)
	local invItemData = IEex_ReadDword(creatureData + 0x4AD8 + special * 0x4)
	if invItemData > 0 then
		local charges1 = IEex_ReadWord(invItemData + 0x18, 0x0)
		local charges2 = IEex_ReadWord(invItemData + 0x1A, 0x0)
		local charges3 = IEex_ReadWord(invItemData + 0x1C, 0x0)
		local resWrapper = IEex_DemandRes(IEex_ReadLString(invItemData + 0xC, 8), "ITM")
		local itemData = 0
		if resWrapper:isValid() then
			itemData = resWrapper:getData()
		end
		if itemData > 0 then
			local maxQuantity = IEex_ReadWord(itemData + 0x38, 0x0)
			local numAbilities = IEex_ReadWord(itemData + 0x68, 0x0)
			if numAbilities >= 1 then
				local maxCharges1 = IEex_ReadWord(itemData + 0xA4, 0x0)
				if maxCharges1 > 0 and bit.band(IEex_ReadDword(itemData + 0xA8), 0x100000) == 0 and ((maxQuantity > 1 and doNotModifyQuantity == false) or (maxQuantity <= 1 and doNotModifyCharges == false)) then
					if parameter2 == 0 then
						charges1 = charges1 + chargeMod1
					elseif parameter2 == 1 then
						charges1 = chargeMod1
					elseif parameter2 == 2 then
						charges1 = math.floor(charges1 * chargeMod1 / 100)
					end
					if charges1 <= 0 then
						charges1 = 1
					elseif goOverMaximum == false then
						if maxQuantity > 1 and charges1 > maxQuantity then
							charges1 = maxQuantity
						elseif maxQuantity <= 1 and charges1 > maxCharges1 then
							charges1 = maxCharges1
						end
					elseif charges1 > 32767 then
						charges1 = 32767
					end
					IEex_WriteWord(invItemData + 0x18, charges1)
				end
			end
			if numAbilities >= 2 then
				local maxCharges2 = IEex_ReadWord(itemData + 0xDC, 0x0)
				if maxCharges2 > 0 and bit.band(IEex_ReadDword(itemData + 0xE0), 0x100000) == 0 and ((maxQuantity > 1 and doNotModifyQuantity == false) or (maxQuantity <= 1 and doNotModifyCharges == false)) then
					if parameter2 == 0 then
						charges2 = charges2 + chargeMod2
					elseif parameter2 == 1 then
						charges2 = chargeMod2
					elseif parameter2 == 2 then
						charges2 = math.floor(charges2 * chargeMod2 / 100)
					end
					if charges2 <= 0 then
						charges2 = 1
					elseif goOverMaximum == false then
						if maxQuantity > 1 and charges2 > maxQuantity then
							charges2 = maxQuantity
						elseif maxQuantity <= 1 and charges2 > maxCharges2 then
							charges2 = maxCharges2
						end
					elseif charges2 > 32767 then
						charges2 = 32767
					end
					IEex_WriteWord(invItemData + 0x1A, charges2)
				end
			end
			if numAbilities >= 3 then
				local maxCharges3 = IEex_ReadWord(itemData + 0x114, 0x0)
				if maxCharges3 > 0 and bit.band(IEex_ReadDword(itemData + 0x118), 0x100000) == 0 and ((maxQuantity > 1 and doNotModifyQuantity == false) or (maxQuantity <= 1 and doNotModifyCharges == false)) then
					if parameter2 == 0 then
						charges3 = charges3 + chargeMod3
					elseif parameter2 == 1 then
						charges3 = chargeMod3
					elseif parameter2 == 2 then
						charges3 = math.floor(charges3 * chargeMod3 / 100)
					end
					if charges3 <= 0 then
						charges3 = 1
					elseif goOverMaximum == false then
						if maxQuantity > 1 and charges3 > maxQuantity then
							charges3 = maxQuantity
						elseif maxQuantity <= 1 and charges3 > maxCharge3 then
							charges3 = maxCharges3
						end
					elseif charges3 > 32767 then
						charges3 = 32767
					end
					IEex_WriteWord(invItemData + 0x1C, charges3)
				end
			end
		end
		resWrapper:free()
		if special >= 15 and special <= 17 then
			local buttonData = creatureData + 0x3828 + 0x3C * (special - 15)
			local header = IEex_ReadWord(buttonData + 0x1E, 0x0)
			if header == 0 then
				IEex_WriteWord(buttonData + 0x18, charges1)
			elseif header == 1 then
				IEex_WriteWord(buttonData + 0x18, charges2)
			elseif header == 2 then
				IEex_WriteWord(buttonData + 0x18, charges3)
			end
		end
	end
end

function EXITMFLG(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	local targetID = IEex_GetActorIDShare(creatureData)
	local flagsToChange = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local special = IEex_ReadDword(effectData + 0x44)
	local invItemData = IEex_ReadDword(creatureData + 0x4AD8 + special * 0x4)
	if invItemData > 0 then
		local slotFlags = IEex_ReadDword(invItemData + 0x20)
		if parameter2 == 0 then
			slotFlags = flagsToChange
		elseif parameter2 == 1 then
			slotFlags = bit.bor(slotFlags, flagsToChange)
		elseif parameter2 == 2 then
			slotFlags = bit.band(slotFlags, (0xFFFFFFFF - flagsToChange))
		end
		IEex_WriteDword(invItemData + 0x20, slotFlags)
	end
end

function MEHOFSUM(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 44,
["target"] = 2,
["parameter1"] = -10,
["timing"] = 1,
["parent_resource"] = "USHOFSUM",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 15,
["target"] = 2,
["parameter1"] = -10,
["timing"] = 1,
["parent_resource"] = "USHOFSUM",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 10,
["target"] = 2,
["parameter1"] = -10,
["timing"] = 1,
["parent_resource"] = "USHOFSUM",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 19,
["target"] = 2,
["parameter1"] = -10,
["timing"] = 1,
["parent_resource"] = "USHOFSUM",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 49,
["target"] = 2,
["parameter1"] = -10,
["timing"] = 1,
["parent_resource"] = "USHOFSUM",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 6,
["target"] = 2,
["parameter1"] = -10,
["timing"] = 1,
["parent_resource"] = "USHOFSUM",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 17,
["target"] = 2,
["parameter1"] = 100,
["parameter2"] = 2,
["timing"] = 1,
["parent_resource"] = "USHOFSUM",
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 1,
["resource"] = "USHOFSUM",
["parent_resource"] = "USHOFSUM",
["source_id"] = targetID
})
end

function MESKLPTC(effectData, creatureData)
	if true then return end
end

function MECLSNAM(effectData, creatureData)
	if true then return end
end

function MEPRDIST(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetX, targetY = IEex_GetActorLocation(targetID)
	local sourceX, sourceY = IEex_GetActorLocation(sourceID)
	IEex_DS("Distance: " .. IEex_GetDistance(targetX, targetY, sourceX, sourceY) .. ", Isometric Distance: " .. IEex_GetDistanceIsometric(targetX, targetY, sourceX, sourceY))
end

function IEex_GetNth(n)
	local nth = "" .. n
	if n < 0 then
		n = n * -1
	end
	if n % 10 == 1 and n % 100 ~= 11 then
		nth = nth .. "st"
	elseif n % 10 == 2 and n % 100 ~= 12 then
		nth = nth .. "nd"
	elseif n % 10 == 3 and n % 100 ~= 13 then
		nth = nth .. "rd"
	else
		nth = nth .. "th"
	end
	return nth
end

opcodenames = {[3] = ex_str_berserk, [5] = ex_str_charm, [12] = ex_str_damage, [17] = ex_str_healing, [20] = ex_str_invisibility, [23] = ex_str_moralefailure, [24] = ex_str_fear, [25] = ex_str_poison, [38] = ex_str_silence, [39] = ex_str_sleep, [40] = ex_str_slow, [45] = ex_str_stun, [58] = ex_str_dispelling, [60] = ex_str_spellfailure, [74] = ex_str_blindness, [76] = ex_str_feeblemindedness, [78] = ex_str_disease, [80] = ex_str_deafness, [93] = ex_str_fatigue, [94] = ex_str_intoxication, [109] = ex_str_paralysis, [124] = ex_str_teleportation, [128] = ex_str_confusion, [134] = ex_str_petrification, [135] = ex_str_polymorphing, [154] = ex_str_entangle, [157] = ex_str_web, [158] = ex_str_grease, [175] = ex_str_hold, [176] = ex_str_movementpenalties, [241] = ex_str_vampiriceffects, [247] = ex_str_beltyn, [255] = ex_str_salamanderauras, [256] = ex_str_umberhulkgaze, [279] = ex_str_animalrage, [281] = ex_str_vitriolicsphere, [294] = ex_str_harpywail, [295] = ex_str_jackalweregaze, [400] = ex_str_hopelessness, [404] = ex_str_nausea, [405] = ex_str_enfeeblement, [412] = ex_str_domination, [414] = ex_str_otiluke, [416] = ex_str_wounding, [419] = ex_str_knockdown, [420] = ex_str_instantdeath, [424] = ex_str_holdundead, [425] = ex_str_controlundead, [428] = ex_str_banishment, [429] = ex_str_energydrain}

classstatnames = {ex_str_barbarian, ex_str_bard, ex_str_cleric, ex_str_druid, ex_str_fighter, ex_str_monk, ex_str_paladin, ex_str_ranger, ex_str_rogue, ex_str_sorcerer, ex_str_wizard}
function MESTATPR(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	IEex_DisplayString(IEex_GetActorName(targetID))
	local alignment = IEex_ReadByte(creatureData + 0x35, 0x0)
	local levelsum = 0
	local classlevels = {}
	for i = 96, 106, 1 do
		local leveli = IEex_GetActorStat(targetID, i)
		if leveli > 0 then
			levelsum = levelsum + leveli
			if i == 102 and bit.band(alignment, 0x3) == 0x3 then
				table.insert(classlevels, {ex_str_blackguard, leveli})
			else
				table.insert(classlevels, {classstatnames[i - 95], leveli})
			end
		end
	end
	local levelstring = ex_str_level .. levelsum
	local numclasses = #classlevels
	if numclasses == 1 then
		levelstring = levelstring .. " " .. classlevels[1][1]
	elseif numclasses > 1 then
		levelstring = levelstring .. " ("
		for i = 1, numclasses, 1 do
			levelstring = levelstring .. classlevels[i][1] .. " " .. classlevels[i][2]
			if i < numclasses then
				levelstring = levelstring .. ", "
			end
		end
		levelstring = levelstring .. ")"
	end
	IEex_DisplayString(levelstring)

	IEex_DisplayString(ex_str_hitpoints .. IEex_ReadSignedWord(creatureData + 0x5C0, 0x0) .. "/" .. IEex_GetActorStat(targetID, 1))
	local armorClassList = IEex_GetActorArmorClass(targetID)
	local ac = armorClassList[1]
	local acslashing = armorClassList[2]
	local acpiercing = armorClassList[3]
	local acbludgeoning = armorClassList[4]
	local acmissile = armorClassList[5]
	if acslashing == acpiercing and acslashing == acbludgeoning and acslashing == acmissile then
		IEex_DisplayString(ex_str_armorclass .. (ac + acslashing))
	else
		IEex_DisplayString(ex_str_acslashing .. ac + acslashing .. "  " .. ex_str_acpiercing .. ac + acpiercing .. "  " .. ex_str_acbludgeoning .. ac + acbludgeoning .. "  " .. ex_str_acmissile .. ac + acmissile)
	end
--[[
	if IEex_GetActorStat(targetID, 7) >= 0 then
		IEex_DisplayString(ex_str_attackbonus .. "+" .. IEex_GetActorStat(targetID, 7))
	else
		IEex_DisplayString(ex_str_attackbonus .. IEex_GetActorStat(targetID, 7))
	end
--]]

	IEex_DisplayString(ex_str_attacksperround .. IEex_GetActorStat(targetID, 8))
	IEex_DisplayString(ex_str_abilityscores)
	IEex_DisplayString(ex_str_strength .. IEex_GetActorStat(targetID, 36) .. "  " .. ex_str_dexterity .. IEex_GetActorStat(targetID, 40) .. "  " .. ex_str_constitution .. IEex_GetActorStat(targetID, 41) .. "  " .. ex_str_intelligence .. IEex_GetActorStat(targetID, 38) .. "  " .. ex_str_wisdom .. IEex_GetActorStat(targetID, 39) .. "  " .. ex_str_charisma .. IEex_GetActorStat(targetID, 42))
	IEex_DisplayString(MEGetStat(targetID, ex_str_slashingresistance, 21, "/-\n") .. MEGetStat(targetID, ex_str_piercingresistance, 23, "/-\n") .. MEGetStat(targetID, ex_str_bludgeoningresistance, 22, "/-\n") .. MEGetStat(targetID, ex_str_missileresistance, 24, "/-\n") .. MEGetStat(targetID, ex_str_fireresistance, 14, "/-\n") .. MEGetStat(targetID, ex_str_coldresistance, 15, "/-\n") .. MEGetStat(targetID, ex_str_electricityresistance, 16, "/-\n") .. MEGetStat(targetID, ex_str_acidresistance, 17, "/-\n") .. MEGetStat(targetID, ex_str_poisonresistance, 74, "/-\n") .. MEGetStat(targetID, ex_str_magicdamageresistance, 73, "/-\n") .. MEGetStat(targetID, ex_str_spellresistance, 18, "/-\n"))
	local damageReduction = IEex_ReadByte(creatureData + 0x758, 0x0)
	local mirrorImagesRemaining = 0
	local stoneskinDamageRemaining = 0
	local sneakAttackModifier = 0
	local extendSpellLevel = 0
	local quickenSpellLevel = 0
	local maximizeSpellLevel = 0
	local safeSpellLevel = 0
	local sneakAttackProtection = false
	local immunities = {}
	local hasImmunities = false
	local isImmuneToSneakAttack = false
	local isNotImmuneToSneakAttack = false
	local canSneakAttackOnEveryHit = false
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		if theopcode == 101 or theopcode == 261 then
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			immunities[theparameter2] = true
			hasImmunities = true
		elseif theopcode == 119 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theparameter2 == 0 and theparameter1 > mirrorImagesRemaining then
				mirrorImagesRemaining = theparameter1
			elseif theparameter2 == 1 and mirrorImagesRemaining == 0 then
				mirrorImagesRemaining = 1
			end
		elseif theopcode == 218 then
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			local theparameter3 = IEex_ReadDword(eData + 0x60)
			if theparameter2 == 0 and theparameter3 > stoneskinDamageRemaining then
				stoneskinDamageRemaining = theparameter3
			end
		elseif theopcode == 288 then
			local theparameter1 = IEex_ReadDword(eData + 0x1C)
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theparameter2 == 192 then
				sneakAttackModifier = sneakAttackModifier + theparameter1
			elseif theparameter2 == 216 then
				local thespecial = IEex_ReadDword(eData + 0x48)
				if thespecial == 0 then
					isImmuneToSneakAttack = true
				elseif thespecial == 1 then
					isNotImmuneToSneakAttack = true
				elseif thespecial == 3 then
					canSneakAttackOnEveryHit = true
				end
			elseif theparameter2 == 234 then
				quickenSpellLevel = quickenSpellLevel + theparameter1
			elseif theparameter2 == 235 then
				safeSpellLevel = safeSpellLevel + theparameter1
			elseif theparameter2 == 238 then
				maximizeSpellLevel = maximizeSpellLevel + theparameter1
			elseif theparameter2 == 239 then
				extendSpellLevel = extendSpellLevel + theparameter1
			end
		elseif theopcode == 436 then
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			if theparameter2 > damageReduction then
				damageReduction = theparameter2
			end
		end
	end)
	if ex_anyone_immune_to_critical_hits_is_immune_to_sneak_attacks and bit.band(IEex_ReadByte(creatureData + 0x89F, 0x0), 0x2) > 0 then
		isImmuneToSneakAttack = true
	end
	if isNotImmuneToSneakAttack then
		isImmuneToSneakAttack = false
	end
	if IEex_GetActorSpellState(targetID, 8) then
		hasImmunities = true
		immunities[420] = true
	end
	if IEex_GetActorSpellState(targetID, 29) then
		hasImmunities = true
		immunities[40] = true
		immunities[109] = true
		immunities[154] = true
		immunities[157] = true
		immunities[158] = true
		immunities[175] = true
		immunities[176] = true
	end
	if damageReduction <= 1 and IEex_GetActorStat(targetID, 101) > 19 then
		IEex_DisplayString(ex_str_damagereduction .. "20/+1")
	elseif damageReduction < 5 and IEex_GetActorSpellState(targetID, 18) then
		IEex_DisplayString(ex_str_damagereduction .. "10/+5")
	elseif damageReduction > 0 then
		IEex_DisplayString(ex_str_damagereduction .. 5 * damageReduction .. "/+" .. damageReduction)
	end
	IEex_DisplayString(ex_str_savingthrows)
	IEex_DisplayString(ex_str_fortitude .. IEex_GetActorStat(targetID, 9) .. "  " .. ex_str_reflex .. IEex_GetActorStat(targetID, 10) .. "  " .. ex_str_will .. IEex_GetActorStat(targetID, 11))
	if hasImmunities then
		local immunitiesString = ex_str_immunities
		local firstImmunity = true
		for key,value in pairs(immunities) do
			if opcodenames[key] ~= nil then
				if firstImmunity == false then
					immunitiesString = immunitiesString .. ", " .. opcodenames[key]
				else
					immunitiesString = immunitiesString .. opcodenames[key]
					firstImmunity = false
				end
			end
		end
		IEex_DisplayString(immunitiesString)
	end
	if IEex_GetActorStat(targetID, 97) > 0 or IEex_GetActorStat(targetID, 98) > 0 or IEex_GetActorStat(targetID, 99) > 0 or IEex_GetActorStat(targetID, 102) > 0 or IEex_GetActorStat(targetID, 103) > 0 or IEex_GetActorStat(targetID, 105) > 0 or IEex_GetActorStat(targetID, 106) > 0 then
		IEex_DisplayString(ex_str_concentrationskill .. IEex_ReadByte(creatureData + 0x7B7, 0x0) + math.floor((IEex_GetActorStat(targetID, 41) - 10) / 2))
	end
	if mirrorImagesRemaining > 0 then
		IEex_DisplayString(ex_str_mirrorimages .. mirrorImagesRemaining)
	end
	if stoneskinDamageRemaining > 0 then
		IEex_DisplayString(ex_str_stoneskins .. stoneskinDamageRemaining)
	end
	IEex_DisplayString(MEGetStat(targetID, ex_str_ironskins, 88, "\n") .. MEGetStat(targetID, ex_str_castingtime, 77, "\n"))
	if IEex_GetActorStat(targetID, 104) > 0 then
		IEex_DisplayString(ex_str_sneakattackdamage .. math.floor((IEex_GetActorStat(targetID, 104) + 1) / 2) + sneakAttackModifier)
	end
	if IEex_GetActorStat(targetID, 79) > 0 then
		IEex_DisplayString(string.gsub(string.gsub(ex_str_55048, "<EXICNAME>", IEex_GetActorName(targetID)), "<EXICVAL1>", IEex_GetActorStat(targetID, 79)))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " casts arcane spells as if " .. IEex_GetActorStat(targetID, 79) .. " levels higher")
	end
	if IEex_GetActorStat(targetID, 53) ~= 100 then
		IEex_DisplayString(string.gsub(string.gsub(ex_str_55049, "<EXICNAME>", IEex_GetActorName(targetID)), "<EXICVAL1>", IEex_GetActorStat(targetID, 53)))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " casts arcane spells with " .. IEex_GetActorStat(targetID, 53) .. "% the normal duration")
	end
	if IEex_GetActorStat(targetID, 80) > 0 then
		IEex_DisplayString(string.gsub(string.gsub(ex_str_55050, "<EXICNAME>", IEex_GetActorName(targetID)), "<EXICVAL1>", IEex_GetActorStat(targetID, 80)))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " casts divine spells as if " .. IEex_GetActorStat(targetID, 80) .. " levels higher")
	end
	if IEex_GetActorStat(targetID, 54) ~= 100 then
		IEex_DisplayString(string.gsub(string.gsub(ex_str_55051, "<EXICNAME>", IEex_GetActorName(targetID)), "<EXICVAL1>", IEex_GetActorStat(targetID, 54)))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " casts divine spells with " .. IEex_GetActorStat(targetID, 54) .. "% the normal duration")
	end
	if extendSpellLevel > 0 then
		IEex_DisplayString(string.gsub(string.gsub(ex_str_55052, "<EXICNAME>", IEex_GetActorName(targetID)), "<EXICVAL1>", extendSpellLevel))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " can extend up to " .. IEex_GetNth(extendSpellLevel) .. "-level spells")
	end
	if maximizeSpellLevel > 0 then
		IEex_DisplayString(string.gsub(string.gsub(ex_str_55053, "<EXICNAME>", IEex_GetActorName(targetID)), "<EXICVAL1>", maximizeSpellLevel))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " can maximize up to " .. IEex_GetNth(maximizeSpellLevel) .. "-level spells")
	end
	if quickenSpellLevel > 0 then
		IEex_DisplayString(string.gsub(string.gsub(ex_str_55054, "<EXICNAME>", IEex_GetActorName(targetID)), "<EXICVAL1>", quickenSpellLevel))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " can quicken up to " .. IEex_GetNth(quickenSpellLevel) .. "-level spells")
	end
	if safeSpellLevel > 0 then
		IEex_DisplayString(string.gsub(string.gsub(ex_str_55055, "<EXICNAME>", IEex_GetActorName(targetID)), "<EXICVAL1>", safeSpellLevel))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " can safen up to " .. IEex_GetNth(safeSpellLevel) .. "-level spells")
	end
	if IEex_GetActorStat(targetID, 76) ~= 0 then
		IEex_DisplayString(string.gsub(ex_str_55056, "<EXICNAME>", IEex_GetActorName(targetID)))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " can cast more than one spell per round")
	end
	if IEex_GetActorStat(targetID, 81) ~= 0 then
		IEex_DisplayString(string.gsub(ex_str_55057, "<EXICNAME>", IEex_GetActorName(targetID)))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " can see invisible creatures")
	end
	if bit.band(IEex_ReadByte(creatureData + 0x89F, 0), 0x2) ~= 0 then
		IEex_DisplayString(string.gsub(ex_str_55058, "<EXICNAME>", IEex_GetActorName(targetID)))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " is protected from critical hits")
	end
	if isImmuneToSneakAttack then
		IEex_DisplayString(string.gsub(ex_str_55059, "<EXICNAME>", IEex_GetActorName(targetID)))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " is protected from sneak attacks")
	end
	if IEex_GetActorSpellState(targetID, 64) then
		IEex_DisplayString(string.gsub(ex_str_55060, "<EXICNAME>", IEex_GetActorName(targetID)))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " deals maximum damage with each hit")
	end
	if canSneakAttackOnEveryHit then
		IEex_DisplayString(string.gsub(ex_str_55061, "<EXICNAME>", IEex_GetActorName(targetID)))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " can sneak attack on each hit")
	end
	if IEex_GetActorStat(targetID, 83) ~= 0 then
		IEex_DisplayString(string.gsub(string.gsub(ex_str_55051, "<EXICNAME>", IEex_GetActorName(targetID)), "<EXICVAL1>", IEex_GetActorStat(targetID, 83)))
--		IEex_DisplayString(IEex_GetActorName(targetID) .. " cannot be reduced below " .. IEex_GetActorStat(targetID, 83) .. " HP")
	end
end

function MEGetStat(targetID, pre, stat, post)
	if IEex_GetActorStat(targetID, stat) == 0 then
		return ""
	else
		return pre .. IEex_GetActorStat(targetID, stat) .. post
	end
end

function MEASSESS(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local armorClassList = IEex_GetActorArmorClass(targetID)
	local ac = armorClassList[1]
	local acslashing = armorClassList[2]
	local acpiercing = armorClassList[3]
	local acbludgeoning = armorClassList[4]
	local acmissile = armorClassList[5]
	local saves = {[1024] = IEex_GetActorStat(targetID, 9), [2048] = IEex_GetActorStat(targetID, 10), [4096] = IEex_GetActorStat(targetID, 11)}
	local spellResistance = IEex_GetActorStat(targetID, 18)
	local opcodeImmunities = {}
	local spellImmunities = {}
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 101 or theopcode == 261 then
			local theparameter2 = IEex_ReadDword(eData + 0x20)
			opcodeImmunities[theparameter2] = true
		elseif theopcode == 206 or theopcode == 290 then
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			spellImmunities[theresource] = true
		end
	end)
	for characterSlot = 0, 5, 1 do
		local playerID = IEex_GetActorIDCharacter(characterSlot)
		local playerData = IEex_GetActorShare(playerID)
		if IEex_IsSprite(playerID, false) then
--[[
			local weaponRES = {"", ""}
			local weaponHand = {1, 2}
			local wearingLightArmor = true
			local equippedSlot = IEex_ReadByte(playerData + 0x4BA4, 0x0)
			local currentAttack = IEex_ReadSignedByte(playerData + 0x5636, 0x0)

			local numWeapons = 0
			if ex_record_attacks_made[playerID] == nil then
				ex_record_attacks_made[playerID] = {0, 0, 0, 0}
			end
			local extraAttacksMade = ex_record_attacks_made[playerID][2]
			local extraMainhandAttacksMade = ex_record_attacks_made[playerID][3]
			local currentAttackPenalty = 0
			IEex_IterateActorEffects(playerID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter1 = IEex_ReadDword(eData + 0x1C)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
				if theopcode == 288 and theparameter2 == 241 then
					if thespecial == 5 or thespecial == 6 then
						numWeapons = numWeapons + 1
						if weaponRES[1] == "" then
							weaponRES[1] = IEex_ReadLString(eData + 0x94, 8)
						else
							weaponRES[2] = IEex_ReadLString(eData + 0x94, 8)
						end
					end

					if (theparameter1 >= 62 and theparameter1 <= 66) or theparameter1 == 68 then
						wearingLightArmor = false
					end
				end
			end)
			if equippedSlot ~= 44 and equippedSlot ~= 46 and equippedSlot ~= 48 and equippedSlot ~= 50 then
				weaponRES[1] = IEex_GetItemSlotRES(playerID, equippedSlot)
			elseif IEex_GetActorStat(playerID, 101) > 0 then
				weaponRES[1] = IEex_GetItemSlotRES(playerID, 10)
			end
			if bit.band(savingthrow, 0x20000) > 0 then
				if IEex_GetActorStat(playerID, 101) > 0 and (equippedSlot == 10 or (equippedSlot == 43 and IEex_GetItemSlotRES(playerID, 10) == IEex_GetItemSlotRES(playerID, 43))) then
					weaponRES[2] = IEex_GetItemSlotRES(playerID, 10)
				elseif equippedSlot == 43 or equippedSlot == 45 or equippedSlot == 47 or equippedSlot == 49 then
					weaponRES[2] = IEex_GetItemSlotRES(playerID, equippedSlot + 1)
				elseif equippedSlot == 44 or equippedSlot == 46 or equippedSlot == 48 or equippedSlot == 50 then
					weaponRES[2] = IEex_GetItemSlotRES(playerID, equippedSlot)
				end
			end
			if bit.band(savingthrow, 0x30000) == 0 then
				weaponRES[1] = IEex_ReadLString(effectData + 0x18, 8)
				local attackPenaltyIncrement = 5
				if IEex_GetActorStat(playerID, 101) > 0 and equippedSlot == 10 then
					attackPenaltyIncrement = 3
				end
				if weaponRES[1] == "" then
					if numWeapons >= 2 and currentAttack == IEex_GetActorStat(playerID, 8) then
		--				currentAttackPenalty = extraAttacksMade * attackPenaltyIncrement
						if equippedSlot == 43 or equippedSlot == 45 or equippedSlot == 47 or equippedSlot == 49 then
							weaponRES[2] = IEex_GetItemSlotRES(playerID, equippedSlot + 1)
						elseif IEex_GetActorStat(playerID, 101) > 0 and (equippedSlot == 10 or IEex_GetItemSlotRES(playerID, 10) == IEex_GetItemSlotRES(playerID, 43)) then
							weaponRES[2] = IEex_GetItemSlotRES(playerID, 10)
						end
					elseif currentAttack >= 1 then
						currentAttackPenalty = (currentAttack - 1) * attackPenaltyIncrement
						if numWeapons >= 2 and currentAttack == IEex_GetActorStat(playerID, 8) - 1 then
		--					currentAttackPenalty = currentAttackPenalty + extraMainhandAttacksMade * attackPenaltyIncrement
						elseif numWeapons < 2 then
		--					currentAttackPenalty = currentAttackPenalty + extraAttacksMade * attackPenaltyIncrement
						end
						weaponRES[1] = IEex_GetItemSlotRES(playerID, equippedSlot)
					else
						weaponRES[1] = parent_resource
					end
				end
			end
			local dualWielding = false
			local dualWieldingPenalty = {0, 0}
		--	if weaponRES[1] ~= "" and weaponRES[2] ~= "" then
			if numWeapons >= 2 then
				dualWielding = true
				dualWieldingPenalty = {6, 10}
				local resWrapper = IEex_DemandRes(weaponRES[2], "ITM")
				if resWrapper:isValid() then
					local itemData = resWrapper:getData()
					local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
					if itemType == 16 or itemType == 19 then
						dualWieldingPenalty[1] = dualWieldingPenalty[1] - 2
						dualWieldingPenalty[2] = dualWieldingPenalty[2] - 2
					end
				end
				resWrapper:free()
				if IEex_GetActorStat(playerID, 103) > 0 and wearingLightArmor then
					dualWieldingPenalty[1] = dualWieldingPenalty[1] - 2
					dualWieldingPenalty[2] = dualWieldingPenalty[2] - 6
				else
					if bit.band(IEex_ReadDword(playerData + 0x75C), 0x2) > 0 then
						dualWieldingPenalty[1] = dualWieldingPenalty[1] - 2
						dualWieldingPenalty[2] = dualWieldingPenalty[2] - 2
					end
					if bit.band(IEex_ReadDword(playerData + 0x764), 0x40) > 0 then
						dualWieldingPenalty[2] = dualWieldingPenalty[2] - 4
					end
				end
			end
			local spriteHands = 2
			local animation = IEex_ReadDword(playerData + 0x5C4)
			if extra_hands[animation] ~= nil then
				spriteHands = extra_hands[animation]
			end
			if spriteHands == 4 then
				if weaponRES[2] == "" then
					weaponRES = {weaponRES[1], weaponRES[1], weaponRES[1], weaponRES[1]}
					weaponHand = {1, 1, 1, 1}
				else
					weaponRES = {weaponRES[1], weaponRES[1], weaponRES[2], weaponRES[2]}
					weaponHand = {1, 1, 2, 2}
				end
			elseif spriteHands == 6 then
				if weaponRES[2] == "" then
					weaponRES = {weaponRES[1], weaponRES[1], weaponRES[1], weaponRES[1], weaponRES[1], weaponRES[1]}
					weaponHand = {1, 1, 1, 1, 1, 1}
				else
					weaponRES = {weaponRES[1], weaponRES[1], weaponRES[1], weaponRES[2], weaponRES[2], weaponRES[2]}
					weaponHand = {1, 1, 1, 2, 2, 2}
				end
			end
			local numAttacks = spriteHands
			local hand = 1
			while hand <= numAttacks do
				local res = weaponRES[hand]
				local resWrapper = IEex_DemandRes(res, "ITM")
				if resWrapper:isValid() then
					local itemData = resWrapper:getData()
					local proficiencyFeat = 0
					local isTwoHanded = (bit.band(IEex_ReadDword(itemData + 0x18), 0x2) > 0)
					local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
					if ex_item_type_proficiency[itemType] ~= nil then
						proficiencyFeat = ex_item_type_proficiency[itemType]
					end
					local criticalHitBonus = 0
					local baseCriticalMultiplier = 2
					if ex_item_type_critical[itemType] ~= nil then
						criticalHitBonus = ex_item_type_critical[itemType][1]
						baseCriticalMultiplier = ex_item_type_critical[itemType][2]
					end
					local effectOffset = IEex_ReadDword(itemData + 0x6A)
					local numHeaders = IEex_ReadWord(itemData + 0x68, 0x0)
					for header = 1, numHeaders, 1 do
						local offset = itemData + 0x4A + header * 0x38
						local headerFlags = IEex_ReadDword(offset + 0x26)
		--				local itemRange = 20 * IEex_ReadWord(offset + 0xE, 0x0) + 40
						local itemRange = 16 * IEex_ReadWord(offset + 0xE, 0x0) + 38
						local whirlwindAttackFeatID = ex_feat_name_id["ME_WHIRLWIND_ATTACK"]
						if bit.band(savingthrow, 0x2000000) > 0 and whirlwindAttackFeatID ~= nil and IEex_ReadByte(playerData + 0x744 + whirlwindAttackFeatID, 0x0) >= 2 then
							itemRange = itemRange + 32
						end
						local itemDamageType = IEex_ReadWord(offset + 0x1C, 0x0)
						if IEex_ReadByte(offset, 0x0) == 1 and ((distX <= itemRange and distY <= itemRange) or bit.band(savingthrow, 0x1000000) == 0) then
							local attackRoll = math.random(20) + IEex_GetActorStat(playerID, 32)
							if attackRoll > 20 then
								attackRoll = 20
							elseif attackRoll < 1 then
								attackRoll = 1
							end
							local hit = 0
							local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
							local sourceStateValue = bit.bor(IEex_ReadDword(playerData + 0x5BC), IEex_ReadDword(playerData + 0x920))
							local concealment = 0
							if bit.band(stateValue, 0x20000000) > 0 then
								concealment = 20
							end
							if (bit.band(stateValue, 0x10) > 0 and IEex_GetActorStat(playerID, 81) == 0) or bit.band(sourceStateValue, 0x40000) > 0 then
								concealment = 50
							end
							if bit.band(stateValue, 0xE9) > 0 or IEex_ReadSignedWord(offset + 0x14, 0x0) == 32767 then
								hit = 5
							elseif IEex_GetActorSpellState(playerID, 59) and math.random(100) <= 20 then
								IEex_ApplyEffectToActor(playerID, {
		["opcode"] = 139,
		["target"] = 2,
		["timing"] = 0,
		["duration"] = 0,
		["parameter1"] = 18352,
		["source_id"] = playerID
		})
							elseif IEex_GetActorSpellState(targetID, 59) and math.random(100) <= 50 then
								IEex_ApplyEffectToActor(targetID, {
		["opcode"] = 139,
		["target"] = 2,
		["timing"] = 0,
		["duration"] = 0,
		["parameter1"] = 18353,
		["source_id"] = targetID
		})
							else
								local concealed = false
								if math.random(100) <= concealment then
									concealed = true
								end
								if concealment > 0 and bit.band(IEex_ReadDword(playerData + 0x75C), 0x40) > 0 then
									if not concealed or math.random(100) > concealment then
										IEex_ApplyEffectToActor(playerID, {
		["opcode"] = 139,
		["target"] = 2,
		["timing"] = 0,
		["duration"] = 0,
		["parameter1"] = ex_tra_55390,
		["source_id"] = playerID
		})
										concealed = false
									else
										IEex_ApplyEffectToActor(playerID, {
		["opcode"] = 139,
		["target"] = 2,
		["timing"] = 0,
		["duration"] = 0,
		["parameter1"] = ex_tra_55391,
		["source_id"] = playerID
		})
									end
								end
								if concealed then
									IEex_ApplyEffectToActor(playerID, {
		["opcode"] = 139,
		["target"] = 2,
		["timing"] = 0,
		["duration"] = 0,
		["parameter1"] = ex_tra_55392,
		["source_id"] = playerID
		})
								else
									local attackBonus = IEex_GetActorBaseAttackBonus(playerID) + IEex_GetActorStat(playerID, 7) + IEex_ReadSignedWord(offset + 0x14, 0x0) - IEex_ReadSignedWord(effectData + 0x44, 0x0) - currentAttackPenalty
									if proficiencyFeat > 0 then
										attackBonus = attackBonus + tonumber(IEex_2DAGetAtStrings("WSPECIAL", "HIT", tostring(IEex_ReadByte(playerData + ex_feat_id_offset[proficiencyFeat], 0x0))))
		--								attackBonus = attackBonus + ex_proficiency_attack[IEex_ReadByte(playerData + ex_feat_id_offset[proficiencyFeat], 0x0)]
									end
									if IEex_ReadByte(playerData + 0x24, 0x0) >= 200 then
										attackBonus = attackBonus + ex_difficulty_attack_bonus[IEex_GetGameDifficulty()]
									end
									if IEex_GetActorStat(playerID, 103) > 0 then
										local favoredEnemyBonus = 0
										local enemyRace = IEex_ReadByte(creatureData + 0x26, 0x0)
										for i = 7, 0, -1 do
											local favoredEnemy = IEex_ReadByte(playerData + 0x7F7 + i, 0x0)
											if favoredEnemy ~= 255 then
												favoredEnemyBonus = favoredEnemyBonus + 1
											end
											if favoredEnemy == enemyRace then
												attackBonus = attackBonus + favoredEnemyBonus
											end
										end
									end
									if weaponHand[hand] == 1 then
										attackBonus = attackBonus - dualWieldingPenalty[1] + IEex_ReadSignedByte(playerData + 0x9F8, 0x0)
									else
										attackBonus = attackBonus - dualWieldingPenalty[2] + IEex_ReadSignedByte(playerData + 0x9FC, 0x0)
									end
									if bit.band(headerFlags, 0x20000) > 0 then
										criticalHitBonus = criticalHitBonus + 1
									end
									if bit.band(IEex_ReadDword(playerData + 0x75C), 0x40000000) > 0 then
										criticalHitBonus = criticalHitBonus + 1
									end
		--							if IEex_GetActorSpellState(playerID, 56) then
										criticalHitBonus = criticalHitBonus + IEex_ReadSignedByte(playerData + 0x936, 0x0)
		--							end
									local attackStatBonus = 0
									if bit.band(headerFlags, 0x1) > 0 then
										attackStatBonus = math.floor((IEex_GetActorStat(playerID, 36) - 10) / 2)
									end
									if (itemType == 16 or itemType == 19) and bit.band(IEex_ReadDword(playerData + 0x764), 0x80) > 0 then
										local dexterityBonus = math.floor((IEex_GetActorStat(playerID, 40) - 10) / 2)
										if dexterityBonus > attackStatBonus then
											attackStatBonus = dexterityBonus
										end
									end
									attackBonus = attackBonus + attackStatBonus
									for i = 1, 5, 1 do
										if IEex_GetActorSpellState(playerID, i + 75) or IEex_GetActorSpellState(playerID, i + 80) then
											attackBonus = attackBonus - i
										end
									end
									local armorClassList = IEex_GetActorArmorClass(targetID)
									local ac = armorClassList[1]
									local acslashing = armorClassList[2]
									local acpiercing = armorClassList[3]
									local acbludgeoning = armorClassList[4]
									local acmissile = armorClassList[5]
									if itemDamageType == 3 or (itemDamageType == 7 and acslashing <= acpiercing) or (itemDamageType == 8 and acslashing <= acbludgeoning) then
										ac = ac + acslashing
									elseif itemDamageType == 1 or (itemDamageType == 6 and acpiercing <= acbludgeoning) or (itemDamageType == 7 and acpiercing <= acslashing) then
										ac = ac + acpiercing
									elseif itemDamageType == 2 or (itemDamageType == 6 and acbludgeoning <= acpiercing) or (itemDamageType == 8 and acbludgeoning <= acslashing) then
										ac = ac + acbludgeoning
									elseif itemDamageType == 4 or itemDamageType == 9 then
										ac = ac + acmissile
									end
--]]
			local schoolDCAdjust = {IEex_GetActorStat(playerID, 222) * 2, IEex_GetActorStat(playerID, 220) * 2, IEex_GetActorStat(playerID, 221) * 2, IEex_GetActorStat(playerID, 219) * 2, IEex_GetActorStat(playerID, 219) * 2, IEex_GetActorStat(playerID, 220) * 2, IEex_GetActorStat(playerID, 221) * 2, IEex_GetActorStat(playerID, 222) * 2}
			local kit = IEex_GetActorStat(playerID, 89)
			for i = 1, 8, 1 do
				if bit.band(kit, 2 ^ (i + 5)) > 0 then
					schoolDCAdjust[i] = schoolDCAdjust[i] + 2
				end
			end
			local specificSpellDCAdjust = {}
			IEex_IterateActorEffects(playerID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				if theopcode == 288 and theparameter2 == 236 and bit.band(thesavingthrow, 0x10000) == 0 then
					local theparameter1 = IEex_ReadDword(eData + 0x1C)
					local theresource = IEex_ReadLString(eData + 0x30, 8)
					local thespecial = IEex_ReadDword(eData + 0x48)
					if bit.band(thesavingthrow, 0x20000) == 0 then
						if theresource == "" then
							for i = 1, 8, 1 do
								schoolDCAdjust[i] = schoolDCAdjust[i] + theparameter1
							end
						else
							if specificSpellDCAdjust[theresource] == nil then
								specificSpellDCAdjust[theresource] = theparameter1
							else
								specificSpellDCAdjust[theresource] = specificSpellDCAdjust[theresource] + theparameter1
							end
						end
					else
						if thespecial == -1 then
							for i = 1, 8, 1 do
								schoolDCAdjust[i] = schoolDCAdjust[i] + theparameter1
							end
						elseif thespecial >= 1 and thespecial <= 8 then
							schoolDCAdjust[thespecial] = schoolDCAdjust[thespecial] + theparameter1
						end
					end
				end
			end)
			local statDCAdjust = {math.floor((IEex_GetActorStat(playerID, 42) - 10) / 2), math.floor((IEex_GetActorStat(playerID, 39) - 10) / 2), math.floor((IEex_GetActorStat(playerID, 39) - 10) / 2), math.floor((IEex_GetActorStat(playerID, 39) - 10) / 2), math.floor((IEex_GetActorStat(playerID, 39) - 10) / 2), math.floor((IEex_GetActorStat(playerID, 42) - 10) / 2), math.floor((IEex_GetActorStat(playerID, 38) - 10) / 2), math.floor((IEex_GetActorStat(playerID, 39) - 10) / 2), }
			local spells = IEex_FetchSpellInfo(playerID, {1, 2, 3, 4, 5, 6, 7, 8})
			for cType, levelList in pairs(spells) do
				for i = 1, 9, 1 do
					if #levelList >= i then
						local levelI = levelList[i]
						local maxCastable = levelI[1]
						local sorcererCastableCount = levelI[2]
						local levelISpells = levelI[3]
						if #levelISpells > 0 and (sorcererCastableCount > 0 or (cType ~= 1 and cType ~= 6)) then
							for i2, spell in ipairs(levelISpells) do
								local resref = spell["resref"]
								local extraSpellInfo = ex_augury_spells[resref]
								if extraSpellInfo ~= nil then
									local dc = 10 + i + statDCAdjust[cType]
									if extraSpellInfo["savebonus"] ~= nil then
										dc = dc + extraSpellInfo["savebonus"]
									end
									if specificSpellDCAdjust[resref] ~= nil then
										dc = dc + specificSpellDCAdjust[resref]
									end
									if state_save_penalties[resref] ~= nil then
										if IEex_GetActorState(targetID, state_save_penalties[resref][1]) then
											dc = dc + state_save_penalties[resref][2]
										end
									end
									local resWrapper = IEex_DemandRes(resref, "SPL")
									local spellData = 0
									if resWrapper:isValid() then
										spellData = resWrapper:getData()
										local nameRef = IEex_ReadDword(spellData + 0x8)
										local school = IEex_ReadByte(spellData + 0x25, 0x0)
										if ex_trueschool[resref] ~= nil then
											school = ex_trueschool[resref]
										end
										if school >= 1 and school <= 8 then
											dc = dc + schoolDCAdjust[school]
										end
										local percentChance = -1
										if extraSpellInfo["savingthrow"] ~= nil then
											percentChance = (dc - saves[extraSpellInfo["savingthrow"]] - 1) * 5
											if percentChance > 95 then
												percentChance = 95
											elseif percentChance < 5 then
												percentChance = 5
											end
											if extraSpellInfo["savingthrow2"] ~= nil then
												local percentChance2 = (dc - saves[extraSpellInfo["savingthrow2"]] - 1) * 5
												if percentChance2 > 95 then
													percentChance2 = 95
												elseif percentChance2 < 5 then
													percentChance2 = 5
												end
												percentChance = math.floor(percentChance * percentChance2)
											end
										end
										if opcodeImmunities[extraSpellInfo["opcode"]] ~= nil or spellImmunities[resref] ~= nil then
											percentChance = 0
										end
										if extraSpellInfo["MESPLPRT"] ~= nil then
											for k, v in ipairs(extraSpellInfo["MESPLPRT"]) do
												local protectionType = v[3]
												local checkID = targetID
												local checkData = IEex_GetActorShare(checkID)
												if protectionType == 0 then
													local match_opcode = v[2]
													local targetRace = IEex_ReadByte(checkData + 0x26, 0x0)
													local targetSubrace = IEex_ReadByte(checkData + 0x7FF, 0x0)
													if (match_opcode == 39 and (targetRace == 2 or targetRace == 3 or targetRace == 183)) or ((match_opcode == 109 or match_opcode == 175) and ((targetRace == 4 and targetSubrace == 2) or targetRace == 185)) then
														percentChance = 0
													elseif ((match_opcode == 55 or match_opcode == 420) and IEex_GetActorSpellState(checkID, 8)) or ((match_opcode == 40 or match_opcode == 109 or match_opcode == 154 or match_opcode == 157 or match_opcode == 158 or match_opcode == 175 or match_opcode == 176) and IEex_GetActorSpellState(checkID, 29)) then
														percentChance = 0
													elseif ((match_opcode == 24 or match_opcode == 236) and IEex_GetActorStat(checkID, 102) >= 2) or (match_opcode == 25 and (IEex_GetActorStat(checkID, 99) >= 9 or IEex_GetActorStat(checkID, 101) >= 11)) or (match_opcode == 78 and (IEex_GetActorStat(checkID, 101) >= 5 or IEex_GetActorStat(checkID, 102) >= 1)) then
														percentChance = 0
													elseif (match_opcode == 5 or match_opcode == 412) and IEex_GetActorSpellState(checkID, 1) and playerData > 0 and bit.band(IEex_ReadByte(playerData + 0x35, 0x0), 0x3) == 0x3 then
														percentChance = 0
													else
														IEex_IterateActorEffects(checkID, function(eData)
															local theopcode = IEex_ReadDword(eData + 0x10)
															local theparameter2 = IEex_ReadDword(eData + 0x20)
															if (theopcode == 101 or theopcode == 261) and theparameter2 == match_opcode then
																percentChance = 0
															end
														end)
													end
												elseif protectionType == 1 then
													local protectionRES = v[1]
													IEex_IterateActorEffects(checkID, function(eData)
														local theopcode = IEex_ReadDword(eData + 0x10)
														local theresource = IEex_ReadLString(eData + 0x30, 8)
														if (theopcode == 206 or theopcode == 290) and theresource == protectionRES then
															percentChance = 0
														end
													end)
												elseif protectionType == 2 then
													local match_state = v[2]
													local stateValue = bit.bor(IEex_ReadDword(checkData + 0x5BC), IEex_ReadDword(checkData + 0x920))
													if bit.band(stateValue, match_state) > 0 then
														percentChance = 0
													end
												elseif protectionType == 3 then
													local match_spellState = v[2]
													if IEex_GetActorSpellState(checkID, match_spellState) then
														percentChance = 0
													end
												elseif protectionType == 4 then
													local match_value = v[1]
													local match_stat = bit.band(v[2], 0xFFFF)
													local statOperator = bit.band(v[2], 0xFF000000)
													local statValue = IEex_GetActorStat(checkID, match_stat)
													if (statOperator == 0 and statValue >= match_value) or (statOperator == 1 and statValue == match_value) or (statOperator == 2 and bit.band(statValue, match_value) == match_value) or (statOperator == 3 and bit.band(statValue, match_value) > 0) then
														percentChance = 0
													end
												elseif protectionType == 5 then
													local match_value = v[1]
													local match_offset = bit.band(v[2], 0xFFFF)
													local readSize = bit.band(v[2], 0xFF0000)
													local statOperator = bit.band(v[2], 0xFF000000)
													local statValue = 0
													if readSize == 2 then
														statValue = IEex_ReadSignedWord(checkData + match_offset, 0x0)
													elseif readSize == 4 then
														statValue = IEex_ReadDword(checkData + match_offset)
													elseif readSize > 4 then
														statValue = IEex_ReadLString(checkData + match_offset, readSize)
													else
														statValue = IEex_ReadSignedByte(checkData + match_offset, 0x0)
													end
													if (statOperator == 0 and statValue >= match_value) or (statOperator == 1 and statValue == match_value) or (statOperator == 2 and bit.band(statValue, match_value) == match_value) or (statOperator == 3 and bit.band(statValue, match_value) > 0) then
														percentChance = 0
													end
												elseif protectionType == 6 then
													local race = IEex_ReadByte(checkData + 0x26, 0x0)
													local match_race1 = bit.band(v[2], 0xFF)
													local match_race2 = bit.band(v[2], 0xFF00)
													local match_race3 = bit.band(v[2], 0xFF0000)
													local match_race4 = bit.band(v[2], 0xFF000000)
													if race == match_race1 or race == match_race2 or race == match_race3 or race == match_race4 then
														percentChance = 0
													end
												elseif protectionType == 7 then
													local general = IEex_ReadByte(checkData + 0x25, 0x0)
													local match_general1 = bit.band(v[2], 0xFF)
													local match_general2 = bit.band(v[2], 0xFF00)
													local match_general3 = bit.band(v[2], 0xFF0000)
													local match_general4 = bit.band(v[2], 0xFF000000)
													if general == match_general1 or general == match_general2 or general == match_general3 or general == match_general4 then
														percentChance = 0
													end
												elseif protectionType == 8 then
													local match_value = v[1]
													local match_stat = bit.band(v[2], 0xFFFF)
													local statOperator = bit.band(v[2], 0xFF000000)
													local statValue = math.abs(IEex_GetActorStat(targetID, match_stat) - IEex_GetActorStat(playerID, match_stat))
													if (statOperator == 0 and statValue >= match_value) or (statOperator == 1 and statValue == match_value) or (statOperator == 2 and bit.band(statValue, match_value) == match_value) or (statOperator == 3 and bit.band(statValue, match_value) > 0) then
														percentChance = 0
													end
												end
											end
										end
										if extraSpellInfo["MESPLPR2"] ~= nil then
											for k, v in ipairs(extraSpellInfo["MESPLPR2"]) do
												local protectionType = v[2]
												local checkID = targetID
												local checkData = IEex_GetActorShare(checkID)
												local general = IEex_ReadByte(checkData + 0x25, 0x0)
												local race = IEex_ReadByte(checkData + 0x26, 0x0)
												local specifics = IEex_ReadByte(checkData + 0x33, 0x0)
												local gender = IEex_ReadByte(checkData + 0x34, 0x0)
												local alignment = IEex_ReadByte(checkData + 0x35, 0x0)
												local animation = IEex_ReadDword(checkData + 0x5C4)
												local subrace = IEex_ReadByte(checkData + 0x7FF, 0x0)
												local stateValue = bit.bor(IEex_ReadDword(checkData + 0x5BC), IEex_ReadDword(checkData + 0x920))
												if protectionType == 0 then
													percentChance = 0
												elseif protectionType == 1 and general == 4 then
													percentChance = 0
												elseif protectionType == 3 then
													local baseFireResistance = IEex_ReadByte(checkData + 0x5F1, 0x0)
													if animation == 29456 or animation == 57896 or animation == 60376 or ((animation == 32517 or animation == 32518 or animation == 59176 or animation == 60507 or animation == 62216) and baseFireResistance >= 50) then
														percentChance = 0
													end
												elseif protectionType == 5 and general == 1 then
													percentChance = 0
												elseif protectionType == 7 and general == 2 then
													percentChance = 0
												elseif protectionType == 9 and (race == 152 or race == 161) then
													percentChance = 0
												elseif protectionType == 11 then
													if animation == 60313 or animation == 60329 or animation == 60337 then
														percentChance = 0
													end
												elseif protectionType == 13 then
													if v[1] == 0 then
														v[1] = 5
													end
													local animationData = IEex_ReadDword(checkData + 0x50F0)
													if animationData > 0 and IEex_ReadByte(animationData + 0x3E4, 0x0) >= v[1] then
														percentChance = 0
													end
												elseif protectionType == 15 and (race == 2 or race == 183) then
													percentChance = 0
												elseif protectionType == 17 then
													if animation == 59225 or animation == 59385 then
														percentChance = 0
													end
												elseif protectionType == 19 and race == 3 then
													percentChance = 0
												elseif protectionType == 21 and (general == 1 or general == 2) then
													percentChance = 0
												elseif protectionType == 23 then
													if bit.band(stateValue, 0x40000) > 0 then
														percentChance = 0
													end
												elseif protectionType == 25 then
													local baseColdResistance = IEex_ReadByte(checkData + 0x5F2, 0x0)
													if animation == 29187 or animation == 31491 or animation == 57656 or animation == 58201 or animation == 58664 or animation == 59192 or animation == 59244 or animation == 59337 or animation == 60184 or animation == 60392 or animation == 60427 or ((animation == 4097 or animation == 59176) and baseColdResistance >= 50) then
														percentChance = 0
													end
												elseif protectionType == 27 and (race == ex_construct_race or specifics == 115) then
													percentChance = 0
												elseif protectionType == 29 then
													if animation == 59144 then
														percentChance = 0
													end
												elseif protectionType == 31 then
													if animation == 60313 or animation == 60329 or animation == 60337 or general == 4 then
														percentChance = 0
													end
												elseif protectionType == 33 and bit.band(alignment, 0x3) == 0x1 then
													percentChance = 0
												elseif protectionType == 35 and bit.band(alignment, 0x3) == 0x2 then
													percentChance = 0
												elseif protectionType == 37 and bit.band(alignment, 0x3) == 0x3 then
													percentChance = 0
												elseif protectionType == 39 and IEex_GetActorStat(targetID, 102) > 0 then
													percentChance = 0
												elseif protectionType == 41 and IEex_IsSprite(playerID, true) then
													local targetAlignment = IEex_ReadByte(creatureData + 0x35, 0x0)
													local sourceAlignment = IEex_ReadByte(playerData + 0x35, 0x0)
													if bit.band(targetAlignment, 0x3) == bit.band(sourceAlignment, 0x3) then
														percentChance = 0
													end
												elseif protectionType == 43 and targetID == playerID then
													percentChance = 0
												elseif protectionType == 45 then
													if animation == 58280 or animation == 57912 or animation == 57938 or animation == 58008 or animation == 59368 or animation == 59385 or animation == 62475 or animation == 62491 then
														percentChance = 0
													end
												elseif protectionType == 47 then
													if general == 4 or race == ex_construct_race or specifics == 115 then
														percentChance = 0
													end
												elseif protectionType == 49 and IEex_IsSprite(playerID, true) then
													if IEex_CompareActorAllegiances(targetID, playerID) == 1 then
														percentChance = 0
													end
												elseif protectionType == 51 and IEex_IsSprite(sourceID, true) then
													if IEex_CompareActorAllegiances(targetID, playerID) == -1 then
														percentChance = 0
													end
												elseif protectionType == 53 then
													local baseFireResistance = IEex_ReadByte(checkData + 0x5F1, 0x0)
													local baseColdResistance = IEex_ReadByte(checkData + 0x5F2, 0x0)
													if animation == 29456 or animation == 57896 or animation == 60376 or ((animation == 32517 or animation == 32518 or animation == 59176 or animation == 60507 or animation == 62216) and baseFireResistance >= 50) or animation == 29187 or animation == 31491 or animation == 57656 or animation == 58201 or animation == 58664 or animation == 59192 or animation == 59244 or animation == 59337 or animation == 60184 or animation == 60392 or animation == 60427 or ((animation == 4097 or animation == 59176) and baseColdResistance >= 50) then
														percentChance = 0
													end
												elseif protectionType == 55 then
													if general == 4 or race == ex_construct_race or specifics == 115 or race == ex_fiend_race or race == 152 or race == 161 or race == 210 or race == 190 then
														percentChance = 0
													end
												elseif protectionType == 57 and gender == 1 then
													percentChance = 0
												elseif protectionType == 59 and bit.band(alignment, 0x30) == 0x10 then
													percentChance = 0
												elseif protectionType == 61 and bit.band(alignment, 0x30) == 0x30 then
													percentChance = 0
												elseif protectionType == 64 then
													if animation == 59400 or animation == 59416 or animation == 59426 or animation == 59448 or animation == 59458 or animation == 59481 or animation == 59496 or animation == 59512 or animation == 59528 or animation == 59609 or animation == 59641 then
														percentChance = 0
													end
												elseif protectionType == 66 and IEex_GetActorSpellState(checkID, 38) then
													percentChance = 0
												elseif protectionType == 68 then
													if bit.band(stateValue, 0x10000000) > 0 then
														percentChance = 0
													end
												elseif protectionType == 70 then
													if animation == 32513 or animation == 61427 then
														percentChance = 0
													end
												elseif protectionType == 72 then
													if bit.band(stateValue, 0x1000) > 0 then
														percentChance = 0
													end
												elseif protectionType == 82 then
													if race == 183 or (race == 2 and subrace == 1) then
														percentChance = 0
													end
												elseif protectionType == 84 then
													if race == 185 or (race == 4 and subrace == 2) then
														percentChance = 0
													end
												elseif protectionType == 88 then
													local areaData = IEex_ReadDword(checkData + 0x12)
													if areaData > 0 and bit.band(IEex_ReadWord(areaData + 0x40, 0x0), 0x1) > 0 then
														percentChance = 0
													end
												elseif protectionType == 90 then
													if animation == 61264 or animation == 61280 or animation == 61296 then
														percentChance = 0
													end
												elseif protectionType == 92 then
													if race == ex_fiend_race or race == 152 or race == 161 or race == 210 then
														percentChance = 0
													end
												elseif protectionType == 94 then
													if general == 4 or race == ex_construct_race or specifics == 115 or race == 190 then
														percentChance = 0
													end
												elseif protectionType == 96 then
													if general == 4 or race == ex_construct_race or specifics == 115 or animation == 29442 or (animation >= 30976 and animation <= 30979) or race == 190 then
														percentChance = 0
													end
												elseif protectionType == 98 then
													if race == 183 or (race == 2 and subrace == 1) or race == 185 or (race == 4 and subrace == 2) then
														percentChance = 0
													end
												elseif protectionType == 100 then
													if race == 183 or (race == 2 and subrace == 1) or race == 185 or (race == 4 and subrace == 2) or animation == 58153 or animation == 58201 or animation == 58217 or animation == 59656 or animation == 59672 or animation == 60313 or animation == 60329 or animation == 60337 then
														percentChance = 0
													end
												elseif protectionType == 102 then
													if race == ex_fiend_race then
														percentChance = 0
													end
												elseif protectionType == 104 then
													if race == ex_fiend_race or general == 4 then
														percentChance = 0
													end
												elseif protectionType == 106 then
													if parameter1 == 0 then
														parameter1 = 50
													end
													if IEex_ReadSignedWord(checkData + 0x720, 0x0) >= parameter1 or IEex_GetActorSpellState(checkID, 184) then
														percentChance = 0
													end
												elseif protectionType == 108 then
													if IEex_GetActorSpellState(checkID, 182) or IEex_GetActorSpellState(checkID, 189) then
														percentChance = 0
													end
												elseif protectionType == 110 then
													if race == 168 and animation ~= 59545 and animation ~= 61961 and animation ~= 61976 then
														percentChance = 0
													end
												elseif protectionType == 112 then
													if general == 1 or general == 5 then
														percentChance = 0
													end
												elseif protectionType == 114 then
													if general == 4 or race == ex_construct_race or specifics == 115 or (race == ex_fiend_race and alignment == 0x33) then
														percentChance = 0
													end
												elseif protectionType == 116 then
													if IEex_GetItemSlotRES(checkID, 44 + IEex_ReadByte(checkData + 0x4C68, 0x0) * 2) ~= "" then
														percentChance = 0
													end
												elseif protectionType == 118 then
													if race == ex_construct_race or specifics == 115 or race == 190 then
														percentChance = 0
													end
												end
											end
										end
										
										
									end
									resWrapper:free()
								end
							end
						end
					end
				end
			end
		end
	end

end

----------------------------------------------------------------
-- Functions which can be used by Opcode 502 (Screen Effects) --
----------------------------------------------------------------
--[[
I'm not sure how closely these correspond to the actual projectile types in IWD2; 
 these are just my guesses of the different types. 
0: No Projectile
1: Single Target
2: Pillar
3: Magic Missile
4: Passes Through Target
5: Passes Through Target, Bounces Off Walls
6: Area of Effect
7: Cone
8: Skull Trap
9: Agannazar's Scorcher
10: Call Lightning Chain
11: Wall
12: Spiritual Wrath
13: Travel Door
14: Cow
15: Chain Lightning
16: Whirlwind
--]]
ex_projectile_type = {
[0] = 0, [1] = 0, [2] = 1, [3] = 6, [4] = 1, [5] = 1, [6] = 1, [7] = 1, [8] = 6, [9] = 1, [10] = 1, [11] = 1, [12] = 1, [13] = 6, [14] = 1, [15] = 1, [16] = 1, [17] = 1, [18] = 6, [19] = 1,
[20] = 1, [21] = 1, [22] = 7, [23] = 2, [24] = 1, [25] = 7, [26] = 7, [27] = 1, [28] = 6, [29] = 1, [30] = 1, [31] = 1, [32] = 1, [33] = 6, [34] = 1, [35] = 1, [36] = 1, [37] = 1, [38] = 6, [39] = 1, 
[40] = 5, [41] = 1, [42] = 6, [43] = 1, [44] = 1, [45] = 1, [46] = 1, [47] = 1, [48] = 1, [49] = 1, [50] = 1, [51] = 1, [52] = 1, [53] = 1, [54] = 1, [55] = 1, [56] = 1, [57] = 6, [58] = 1, [59] = 1, 
[60] = 1, [61] = 1, [62] = 1, [63] = 6, [64] = 1, [65] = 1, [66] = 2, [67] = 6, [68] = 1, [69] = 3, [70] = 3, [71] = 3, [72] = 3, [73] = 3, [74] = 3, [75] = 3, [76] = 3, [77] = 3, [78] = 3, [79] = 1, 
[80] = 6, [81] = 10, [82] = 10, [83] = 10, [84] = 10, [85] = 10, [86] = 10, [87] = 10, [88] = 10, [89] = 10, [90] = 10, [91] = 10, [92] = 6, [93] = 6, [94] = 6, [95] = 6, [96] = 8, [97] = 7, [98] = 6, [99] = 11, 
[100] = 8, [101] = 6, [102] = 1, [103] = 1, [104] = 1, [105] = 1, [106] = 1, [107] = 6, [108] = 1, [109] = 9, 
[110] = 13, [111] = 1, [112] = 1, [113] = 1, [114] = 1, [115] = 1, [116] = 1, [117] = 1, [118] = 1, [119] = 1, 
[120] = 1, [121] = 1, [122] = 1, [123] = 1, [124] = 1, [125] = 1, [126] = 1, [127] = 1, [128] = 1, [129] = 1, 
[130] = 1, [131] = 1, [132] = 1, [133] = 1, [134] = 1, [135] = 1, [136] = 1, [137] = 1, [138] = 1, [139] = 1, 
[140] = 1, [141] = 1, [142] = 1, [143] = 1, [144] = 1, [145] = 1, [146] = 1, [147] = 1, [148] = 1, [149] = 6, 
[150] = 6, [151] = 6, [152] = 6, [153] = 6, [154] = 6, [155] = 6, [156] = 6, [157] = 6, [158] = 6, [159] = 6, 
[160] = 6, [161] = 6, [162] = 6, [163] = 6, [164] = 6, [165] = 6, [166] = 6, [167] = 6, [168] = 6, [169] = 6, 
[170] = 6, [171] = 6, [172] = 6, [173] = 6, [174] = 6, [175] = 6, [176] = 6, [177] = 6, [178] = 6, [179] = 6, 
[180] = 6, [181] = 6, [182] = 6, [183] = 6, [184] = 1, [185] = 1, [186] = 6, [187] = 6, [188] = 1, [189] = 14, 
[190] = 6, [191] = 1, [192] = 1, [193] = 1, [194] = 1, [195] = 2, [196] = 6, [197] = 6, [198] = 6, [199] = 6, 
[200] = 6, [201] = 6, [202] = 6, [203] = 6, [204] = 6, [205] = 6, [206] = 5, [207] = 4, [208] = 1, [209] = 6,
[210] = 15, [211] = 6, [212] = 6, [213] = 6, [214] = 6, [215] = 6, [216] = 6, [217] = 6, [218] = 1, [219] = 1,
[220] = 1, [221] = 1, [222] = 1, [223] = 1, [224] = 1, [225] = 1, [226] = 1, [227] = 1, [228] = 1, [229] = 1,
[230] = 1, [231] = 1, [232] = 1, [233] = 1, [234] = 1, [235] = 6, [236] = 6, [237] = 6, [238] = 6, [239] = 6,
[240] = 6, [241] = 6, [242] = 6, [243] = 6, [244] = 6, [245] = 6, [246] = 6, [247] = 1, [248] = 6, [249] = 6,
[250] = 6, [251] = 1, [252] = 6, [253] = 6, [254] = 6, [255] = 6, [256] = 6, [257] = 6, [258] = 6, [259] = 6,
[260] = 1, [261] = 1, [262] = 1, [263] = 6, [264] = 6, [265] = 1, [266] = 6, [267] = 6, [268] = 1, [269] = 1,
[270] = 6, [271] = 1, [272] = 7, [273] = 6, [274] = 6, [275] = 6, [276] = 6, [277] = 6, [278] = 6, [279] = 6,
[280] = 6, [281] = 6, [282] = 6, [283] = 6, [284] = 6, [285] = 1, [286] = 6, [287] = 6, [288] = 6, [289] = 1,
[290] = 1, [291] = 1, [292] = 1, [293] = 1, [294] = 1, [295] = 6, [296] = 7, [297] = 1, [298] = 1, [299] = 6,
[300] = 6, [301] = 6, [302] = 4, [303] = 1, [304] = 1, [305] = 16, [306] = 6, [307] = 6, [308] = 6, [309] = 6,
[310] = 6, [311] = 6, [312] = 12, [313] = 4, [314] = 1, [315] = 7, [316] = 1, [317] = 6, [318] = 6, [319] = 7,
[320] = 6, [321] = 6, [322] = 6, [323] = 6, [324] = 1, [325] = 3, [326] = 3, [327] = 3, [328] = 3, [329] = 3,
[330] = 3, [331] = 3, [332] = 3, [333] = 3, [334] = 3, [335] = 6, [336] = 6, [337] = 6, [338] = 6, [339] = 6,
[340] = 6, [341] = 6, [342] = 6, [343] = 7, [344] = 1, [345] = 3, [346] = 1, [347] = 1, [348] = 1, [349] = 6,
[350] = 1, [351] = 6, [352] = 1, [353] = 1, [354] = 1, [355] = 1, [356] = 1, [357] = 6, [358] = 6, [359] = 6,
[360] = 8, [361] = 1, [362] = 6, [363] = 6, [364] = 6, [365] = 6, [366] = 6, [367] = 6, [368] = 7, [369] = 6,
[370] = 11, [371] = 6, [372] = 6, [373] = 6, [374] = 7, [375] = 1, [376] = 6, [377] = 6, [378] = 1, [379] = 7,
[380] = 5, [381] = 6, [382] = 7, [383] = 4, [384] = 6, [385] = 6, [386] = 7,
}

--[[
To use the EXSPLDEF function, create an opcode 502 effect in a spell, set the resource to EXSPLDEF (all capitals), and choose parameters.

The EXSPLDEF function works like Spell Deflection, Spell Turning or Spell Trap from the other EE games, except it works against area of effect spells.

parameter1 - Determines the lowest spell level that can be deflected (0 - 9).

parameter2 - Determines the highest spell level that can be deflected (0 - 9).

special - Determines the number of spell levels that can be deflected. If set to -1, there is no limit.

savingthrow - This function uses several extra bits on this parameter:
Bit 17: If set, once the last spell level is deflected, another spell is cast on the creature whose spell
 was deflected. The spell resref is specified by resource2 (in an EFF file). If you aren't using this from an
 EFF file, then the spell resref is set to the resref of the source spell, with an E added at the end.
Bit 18: If set, whenever a spell is deflected, another spell is cast on the creature whose spell
 was deflected. The spell resref is specified by resource3 (in an EFF file). If you aren't using this from an
 EFF file, then the spell resref is set to the resref of the source spell, with an F added at the end.
Bit 19: If set, up to special spells (rather than spell levels) are deflected.
Bit 20: If NOT set, the function will remove all effects of the spell that called EXSPLDEF once the last spell level is deflected.
Bit 21: If set, only spells with the hostile flag, or that deal damage, will be deflected.
Bit 22: If set, the function will reflect rather than deflect the spell.
Bit 23: If set, the function will absorb the spell as with Spell Trap, restoring one of the character's previously-used spells.
Bit 24: If set, spells from allies will not be deflected.
Bit 25: If set, area of effect spells will not be deflected.

--]]
previous_spells_turned = {}
function EXSPLDEF(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local o_parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
	local internal_flags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if bit.band(internal_flags, 0x4000000) > 0 or targetID <= 0 or sourceID <= 0 or targetID == sourceID then return false end
	local o_savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
	local o_parameter1 = IEex_ReadDword(originatingEffectData + 0x18)
	local o_parameter2 = IEex_ReadDword(originatingEffectData + 0x1C)
	local match_spellRES = IEex_ReadLString(originatingEffectData + 0x18, 8)
	local spellRES = IEex_ReadLString(effectData + 0x90, 8)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local resource = IEex_ReadLString(effectData + 0x2C, 8)
	local spellLevel = IEex_ReadDword(effectData + 0x14)
	local endSpellRES = IEex_ReadLString(originatingEffectData + 0x6C, 8)
	local repeatSpellRES = IEex_ReadLString(originatingEffectData + 0x74, 8)
	if endSpellRES == "" then
		endSpellRES = o_parent_resource .. "E"
	end
	if repeatSpellRES == "" then
		repeatSpellRES = o_parent_resource .. "F"
	end
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	local sourceSpell = ex_source_spell[spellRES]
	if sourceSpell == nil then
		sourceSpell = spellRES
	end
	local classSpellLevel = 0
	if IEex_IsSprite(sourceID, true) then
		classSpellLevel = IEex_GetClassSpellLevel(sourceID, casterClass, sourceSpell)
		if classSpellLevel == 0 and IEex_GetActorStat(sourceID, 105) > 0 then
			classSpellLevel = IEex_GetClassSpellLevel(sourceID, 10, sourceSpell)
		end
	end
	if ex_bypass_spell_deflection[sourceSpell] ~= nil then return false end
--	if spellLevel <= 0 and bit.band(o_savingthrow, 0x10000) == 0 and (classSpellLevel == 0 or resource ~= "MESPLSAV") then return false end
	if bit.band(o_savingthrow, 0x1000000) > 0 and IEex_CompareActorAllegiances(sourceID, targetID) == 1 then return false end
	local o_special = IEex_ReadDword(originatingEffectData + 0x44)
	local time_applied = IEex_ReadDword(effectData + 0x68)
	local projectile = 1
	local isHostile = false
	local resWrapper = IEex_DemandRes(sourceSpell, "SPL")
	local spellData = 0
	if resWrapper:isValid() then
		spellData = resWrapper:getData()
		isHostile = (bit.band(IEex_ReadDword(spellData + 0x18), 0x400) > 0)
		local spellType = IEex_ReadWord(spellData + 0x1C, 0x0)
		if classSpellLevel == 0 and (spellType == 1 or spellType == 2) then
			classSpellLevel = IEex_ReadDword(spellData + 0x34)
		end
		local realCasterLevel = IEex_ReadByte(effectData + 0xC4, 0x0)
		local numHeaders = IEex_ReadWord(spellData + 0x68, 0x0)
		
		for i = 1, numHeaders, 1 do
			if realCasterLevel >= IEex_ReadWord(spellData + 0x5A + 0x28 * i + 0x10, 0x0) then
				projectile = IEex_ReadWord(spellData + 0x5A + 0x28 * i + 0x26, 0x0)
			end
		end
	end
	resWrapper:free()
	if classSpellLevel < o_parameter1 or classSpellLevel > o_parameter2 then return false end
	if bit.band(o_savingthrow, 0x200000) > 0 and opcode ~= 12 and opcode ~= 25 and opcode ~= 78 and not isHostile then return false end
	local separateDelay = 1
	if ex_projectile_type[projectile] == 3 then
		separateDelay = 15
	end

	if previous_spells_turned["" .. targetID] == nil then
		previous_spells_turned["" .. targetID] = {}
	end
	if previous_spells_turned["" .. targetID]["" .. sourceID] == nil then
		previous_spells_turned["" .. targetID]["" .. sourceID] = {}
	end
	if previous_spells_turned["" .. targetID]["" .. sourceID][sourceSpell] == nil or math.abs(previous_spells_turned["" .. targetID]["" .. sourceID][sourceSpell] - time_applied) > separateDelay then

		if bit.band(o_savingthrow, 0x2000000) > 0 and ex_projectile_type[projectile] >= 4 and ex_projectile_type[projectile] ~= 9 and ex_projectile_type[projectile] ~= 14 and ex_projectile_type[projectile] ~= 15 then return false end
		if o_special == 0 then
			return false
		elseif o_special ~= -1 then
			if bit.band(o_savingthrow, 0x80000) == 0 and classSpellLevel > 0 then
				o_special = o_special - classSpellLevel
				if o_special < 0 then
					o_special = 0
				end
			else
				o_special = o_special - 1
			end
			IEex_WriteDword(originatingEffectData + 0x44, o_special)
		end
--[[
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 206,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["resource"] = spellRES,
["internal_flags"] = 0x4000000,
["source_target"] = targetID,
["source_id"] = targetID
})
--]]
		if bit.band(o_savingthrow, 0x400000) > 0 then
			if ex_projectile_type[projectile] ~= 6 and ex_projectile_type[projectile] ~= 8 and ex_projectile_type[projectile] ~= 11 and ex_projectile_type[projectile] ~= 16 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 430,
["target"] = 2,
["parameter2"] = projectile - 1,
["timing"] = 1,
["resource"] = sourceSpell,
["savingthrow"] = IEex_ReadDword(effectData + 0x3C),
["savebonus"] = IEex_ReadDword(effectData + 0x40),
["source_x"] = IEex_ReadDword(creatureData + 0x8),
["source_y"] = IEex_ReadDword(creatureData + 0xC),
["target_x"] = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0x8),
["target_y"] = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0xC),
["restype"] = IEex_ReadDword(effectData + 0x8C),
["parent_resource"] = sourceSpell,
["resource_flags"] = IEex_ReadDword(effectData + 0x98),
["casterlvl"] = casterlvl,
["internal_flags"] = bit.bor(internal_flags, 0x4000000),
["source_target"] = sourceID,
["source_id"] = targetID
})
			else
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = sourceSpell,
["savingthrow"] = IEex_ReadDword(effectData + 0x3C),
["savebonus"] = IEex_ReadDword(effectData + 0x40),
["source_x"] = IEex_ReadDword(creatureData + 0x8),
["source_y"] = IEex_ReadDword(creatureData + 0xC),
["target_x"] = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0x8),
["target_y"] = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0xC),
["restype"] = IEex_ReadDword(effectData + 0x8C),
["parent_resource"] = sourceSpell,
["resource_flags"] = IEex_ReadDword(effectData + 0x98),
["casterlvl"] = casterlvl,
["internal_flags"] = bit.bor(internal_flags, 0x4000000),
["source_target"] = sourceID,
["source_id"] = targetID
})
			end
		end
		if bit.band(o_savingthrow, 0x800000) > 0 then
			local o_casterClass = IEex_ReadByte(originatingEffectData + 0xC5, 0x0)
			local modmemflags = 0x8000000
			if o_casterClass == 0 then
				modmemflags = bit.bor(modmemflags, 0xFF0000)
			elseif o_casterClass == 2 then
				modmemflags = bit.bor(modmemflags, 0x10000)
			elseif o_casterClass == 3 then
				modmemflags = bit.bor(modmemflags, 0x820000)
			elseif o_casterClass == 4 then
				modmemflags = bit.bor(modmemflags, 0x40000)
			elseif o_casterClass == 7 then
				modmemflags = bit.bor(modmemflags, 0x80000)
			elseif o_casterClass == 8 then
				modmemflags = bit.bor(modmemflags, 0x100000)
			elseif o_casterClass == 10 then
				modmemflags = bit.bor(modmemflags, 0x200000)
			elseif o_casterClass == 11 then
				modmemflags = bit.bor(modmemflags, 0x400000)
			end
			local restoreSpellLevel = IEex_GetClassSpellLevel(targetID, o_casterClass, o_parent_resource) - 1
			if restoreSpellLevel == -1 then
				restoreSpellLevel = 9
			end
			if restoreSpellLevel > classSpellLevel then
				restoreSpellLevel = classSpellLevel
			end
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = 1,
["parameter2"] = restoreSpellLevel,
["special"] = 1,
["resource"] = "EXMODMEM",
["savingthrow"] = modmemflags,
["internal_flags"] = 0x4000000,
["source_target"] = targetID,
["source_id"] = targetID
})		
		end
		if bit.band(o_savingthrow, 0x40000) > 0 then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = repeatSpellRES,
["parent_resource"] = repeatSpellRES,
["internal_flags"] = 0x4000000,
["casterlvl"] = IEex_ReadDword(originatingEffectData + 0xC4),
["source_target"] = sourceID,
["source_id"] = targetID
})
		end
		if o_special == 0 then
			if bit.band(o_savingthrow, 0x20000) > 0 then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = endSpellRES,
["parent_resource"] = endSpellRES,
["internal_flags"] = 0x4000000,
["casterlvl"] = IEex_ReadDword(originatingEffectData + 0xC4),
["source_target"] = targetID,
["source_id"] = targetID
})
			end
			if bit.band(o_savingthrow, 0x100000) == 0 then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["duration"] = IEex_GetGameTick() + 1,
["resource"] = o_parent_resource,
["internal_flags"] = 0x4000000,
["source_target"] = targetID,
["source_id"] = targetID
})
--[[
				IEex_RemoveEffectsByResource(targetID, parent_resource)
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 6,
["duration"] = IEex_GetGameTick() + 2,
["resource"] = "USBASEEF",
["internal_flags"] = 0x4000000,
["casterlvl"] = IEex_ReadDword(originatingEffectData + 0xC4),
["source_target"] = targetID,
["source_id"] = targetID
})
--]]
			end
		end
	end
	previous_spells_turned["" .. targetID]["" .. sourceID][sourceSpell] = time_applied
	return true
end

function MEPOLYBL(originatingEffectData, effectData, creatureData)

	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if opcode == 111 and bit.band(savingthrow, 0x10000) == 0 then
		return true
--[[
	elseif opcode == 58 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 9,
["resource"] = "SPIN122",
["source_id"] = targetID
})
--]]
	end
--[[
	local timing = IEex_ReadDword(effectData + 0x20)
	if timing == 2 then
		for i = 43, 50, 1 do
			if IEex_ReadDword(creatureData + 0x4AD8 + i * 0x4) > 0 and IEex_ReadLString(IEex_ReadDword(creatureData + 0x4AD8 + i * 0x4) + 0xC, 8) == parent_resource then
				return true
			end
		end
	end
--]]
	return false
end

function METELEBL(originatingEffectData, effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if opcode == 124 and bit.band(savingthrow, 0x10000) == 0 then
		return true
	end
	return false
end

function MESUMMOD(originatingEffectData, effectData, creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local power = IEex_ReadDword(effectData + 0x10)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local special = IEex_ReadDword(effectData + 0x44)
	local school = IEex_ReadDword(effectData + 0x48)
	local resource = IEex_ReadLString(effectData + 0x2C, 8)
	local vvcresource = IEex_ReadLString(effectData + 0x6C, 8)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local casterClass = IEex_ReadByte(effectData + 0xC5, 0x0)
	local sourceSpell = ex_source_spell[parent_resource]
	if sourceSpell == nil then
		sourceSpell = parent_resource
	end
	local classSpellLevel = 0
	if IEex_IsSprite(sourceID, true) then
		classSpellLevel = IEex_GetClassSpellLevel(sourceID, casterClass, sourceSpell)
	end
	if opcode ~= 67 and opcode ~= 410 and opcode ~= 411 and (opcode ~= 288 or parameter2 ~= 207) then return false end
	local internal_flags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if bit.band(internal_flags, 0x4000000) == 0 then
		local targetID = IEex_GetActorIDShare(creatureData)
		if targetID ~= sourceID or not IEex_IsSprite(targetID) or not IEex_IsSprite(sourceID) then return false end
		local o_spellRES = IEex_ReadLString(originatingEffectData + 0x18, 8)
		local o_spellRES2 = IEex_ReadLString(originatingEffectData + 0x6C, 8)
		local o_spellRES3 = IEex_ReadLString(originatingEffectData + 0x74, 8)
		local o_savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
		if bit.band(o_savingthrow, 0x100000) > 0 and parent_resource ~= o_spellRES and parent_resource ~= o_spellRES2 and parent_resource ~= o_spellRES3 then return false end
		if bit.band(o_savingthrow, 0x200000) > 0 and classSpellLevel > IEex_ReadDword(originatingEffectData + 0x18) then return false end
		if bit.band(o_savingthrow, 0x400000) > 0 and school ~= IEex_ReadDword(originatingEffectData + 0x1C) then return false end
		local o_special = IEex_ReadDword(originatingEffectData + 0x44)
		if bit.band(o_savingthrow, 0x10000) > 0 then
			parameter1 = parameter1 * o_special
		else
			parameter1 = parameter1 + o_special
		end
		if parameter1 <= 0 then return true end
		IEex_WriteDword(effectData + 0x18, parameter1)
	end
	return false
end

function METELEBL(originatingEffectData, effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	if opcode == 124 and bit.band(savingthrow, 0x10000) == 0 then
		return true
	end
	return false
end

function MEACVTYP(originatingEffectData, effectData, creatureData)
	if true then return false end
end

function MESVVTYP(originatingEffectData, effectData, creatureData)
	if true then return false end
end

function MEOPCSPL(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local match_opcode = IEex_ReadDword(originatingEffectData + 0x44)
	local match_parent_resource = IEex_ReadLString(originatingEffectData + 0x18, 8)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	
	if opcode == match_opcode and parent_resource == match_parent_resource then
		return true
	end
	return false
end

previous_attacks_deflected = {}
function MEDEFLEC(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local string = IEex_ReadDword(originatingEffectData + 0x18)
	local types_blocked = IEex_ReadDword(originatingEffectData + 0x1C)
	local savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
	local delay = IEex_ReadDword(originatingEffectData + 0x44)
	local parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
	local damage = IEex_ReadDword(effectData + 0x18)
	local damage_type = IEex_ReadWord(effectData + 0x1E, 0x0)
	local flags = IEex_ReadDword(effectData + 0x44)
	local restype = IEex_ReadDword(effectData + 0x8C)
	local internal_flags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if bit.band(internal_flags, 0x4000000) > 0 then return false end
	local opcode = IEex_ReadDword(effectData + 0xC)
	local effectRES = IEex_ReadLString(effectData + 0x90, 8)
	local isOnHitEffect = false
	local doDeflect = true
	if bit.band(savingthrow, 0x40000) > 0 and math.random(100) > delay then
		doDeflect = false
	elseif bit.band(savingthrow, 0x10000) == 0 and delay > 0 then
		IEex_IterateActorEffects(targetID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			local thevvcresource = IEex_ReadLString(eData + 0x70, 8)
			if theopcode == 0 and bit.band(thesavingthrow, 0x100000) > 0 and theresource == parent_resource and thevvcresource == "MEDEFLEC" then
				doDeflect = false
			end
		end)
	end
	if previous_attacks_deflected["" .. targetID] == nil then
		previous_attacks_deflected["" .. targetID] = {}
	end
	if opcode == 12 and effectRES == "IEEX_DAM" and ((damage_type == 0 and bit.band(types_blocked, 0x2000) > 0) or (damage_type ~= 0 and bit.band(types_blocked, damage_type) > 0)) and ((bit.band(savingthrow, 0x10000) > 0 and delay ~= 0) or (bit.band(savingthrow, 0x10000) == 0 and doDeflect)) then
		if bit.band(savingthrow, 0x400000) > 0 and damage < IEex_ReadSignedWord(creatureData + 0x5C0, 0x0) then return false end
--		effectRES = IEex_ReadLString(effectData + 0x6C, 8)
		effectRES = "IEEX_DAM"
		previous_attacks_deflected["" .. targetID][effectRES] = IEex_GetGameTick()
	elseif bit.band(savingthrow, 0x80000) > 0 and previous_attacks_deflected["" .. targetID]["IEEX_DAM"] == IEex_GetGameTick() and restype == 2 then
		isOnHitEffect = true
	end
	if opcode ~= 12 and isOnHitEffect == false then return false end
	
	if bit.band(savingthrow, 0x200000) > 0 then
		if IEex_GetActorStat(targetID, 101) == 0 and IEex_GetActorStat(targetID, 40) < 19 then return false end
		local hasArmor = false
		local handsUsed = 0
		local spriteHands = 2
		local animation = IEex_ReadDword(creatureData + 0x5C4)
		if extra_hands[animation] ~= nil then
			spriteHands = extra_hands[animation]
		end
--		if IEex_GetActorSpellState(targetID, 241) then
			IEex_IterateActorEffects(targetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				if theopcode == 288 and theparameter2 == 241 then
					local thesavingthrow = IEex_ReadDword(eData + 0x40)
					local thespecial = IEex_ReadByte(eData + 0x48, 0x0)
					if (thespecial >= 3 and thespecial <= 5 and theparameter1 ~= 41) then
						if bit.band(thesavingthrow, 0x20000) == 0 then
							handsUsed = handsUsed + 1
						else
							handsUsed = handsUsed + 2
						end
					elseif thespecial == 1 or thespecial == 3 then
						hasArmor = true
					end
				end
			end)
--		end
--		if hasArmor or ((spriteHands - handsUsed) < 2) then return false end
		if ((spriteHands - handsUsed) < 1) then return false end
	end
	if opcode == 12 and bit.band(savingthrow, 0x400000) > 0 and damage < IEex_ReadSignedWord(creatureData + 0x5C0, 0x0) then return false end
	if bit.band(savingthrow, 0x800000) > 0 then
		local stateValue = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
		if bit.band(stateValue, 0xFE9) ~= 0 then return false end
	end

	if isOnHitEffect or (damage_type == 0 and bit.band(types_blocked, 0x2000) > 0) or (damage_type ~= 0 and bit.band(types_blocked, damage_type) > 0) then
		if doDeflect or isOnHitEffect then
			if bit.band(savingthrow, 0x50000) == 0x10000 and delay ~= -1 and isOnHitEffect == false then
				if delay > 0 then
					delay = delay - 1
					IEex_WriteDword(originatingEffectData + 0x44, delay)
				else
					return false
				end
			end
			if bit.band(savingthrow, 0x50000) == 0 and delay > 0 and isOnHitEffect == false then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 0,
["duration"] = delay,
["resource"] = parent_resource,
["vvcresource"] = "MEDEFLEC",
["parent_resource"] = "MEDEFDEL",
["savingthrow"] = 0x100000,
["internal_flags"] = 0x4000000,
["source_target"] = targetID,
["source_id"] = targetID,
})
			end
			if string ~= -1 and isOnHitEffect == false then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = string,
["resource"] = parent_resource,
["parent_resource"] = "MEDEFSTR",
["internal_flags"] = 0x4000000,
["source_target"] = targetID,
["source_id"] = targetID,
})
			end
			if bit.band(savingthrow, 0x100000) > 0 and IEex_IsSprite(sourceID, false) and targetID ~= sourceID then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = IEex_ReadDword(effectData + 0xC),
["target"] = IEex_ReadDword(effectData + 0x10),
["power"] = IEex_ReadDword(effectData + 0x14),
["parameter1"] = IEex_ReadDword(effectData + 0x18),
["parameter2"] = IEex_ReadDword(effectData + 0x1C),
["timing"] = IEex_ReadDword(effectData + 0x20),
["duration"] = IEex_ReadDword(effectData + 0x24),
["resource"] = IEex_ReadLString(effectData + 0x2C, 8),
["dicenumber"] = IEex_ReadDword(effectData + 0x34),
["dicesize"] = IEex_ReadDword(effectData + 0x38),
["savingthrow"] = IEex_ReadDword(effectData + 0x3C),
["savebonus"] = IEex_ReadDword(effectData + 0x40),
["special"] = IEex_ReadDword(effectData + 0x44),
["school"] = IEex_ReadDword(effectData + 0x48),
["resist_dispel"] = IEex_ReadDword(effectData + 0x58),
["parameter3"] = IEex_ReadDword(effectData + 0x5C),
["parameter4"] = IEex_ReadDword(effectData + 0x60),
["parameter5"] = IEex_ReadDword(effectData + 0x64),
["vvcresource"] = IEex_ReadLString(effectData + 0x6C, 8),
["resource2"] = IEex_ReadLString(effectData + 0x74, 8),
["source_x"] = IEex_ReadDword(creatureData + 0x8),
["source_y"] = IEex_ReadDword(creatureData + 0xC),
["target_x"] = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0x8),
["target_y"] = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0xC),
["restype"] = IEex_ReadDword(effectData + 0x8C),
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["resource_flags"] = IEex_ReadDword(effectData + 0x98),
["impact_projectile"] = IEex_ReadDword(effectData + 0x9C),
["sourceslot"] = IEex_ReadDword(effectData + 0xA0),
["effvar"] = IEex_ReadLString(effectData + 0xA4, 32),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = bit.bor(internal_flags, 0x4000000),
["sectype"] = IEex_ReadDword(effectData + 0x4C),
["source_target"] = sourceID,
["source_id"] = targetID
})
			end
			if bit.band(savingthrow, 0x10000) > 0 and bit.band(savingthrow, 0x20000) > 0 and delay == 0 and isOnHitEffect == false then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["duration"] = IEex_GetGameTick() + 1,
["resource"] = parent_resource,
["internal_flags"] = 0x4000000,
["source_target"] = targetID,
["source_id"] = targetID
})
			end
			return true
		end
	end
	return false
end

function MEDAMPRC(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local percentageModifier = IEex_ReadDword(originatingEffectData + 0x18)
	local types_blocked = IEex_ReadDword(originatingEffectData + 0x1C)
	local savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
	local delay = IEex_ReadDword(originatingEffectData + 0x44)
	local parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
	local damage = IEex_ReadDword(effectData + 0x18)
	local damage_type = IEex_ReadWord(effectData + 0x1E, 0x0)
	local dicenumber = IEex_ReadDword(effectData + 0x34)
	local flags = IEex_ReadDword(effectData + 0x44)
	local restype = IEex_ReadDword(effectData + 0x8C)
	local internal_flags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if bit.band(internal_flags, 0x4000000) > 0 then return false end
	local opcode = IEex_ReadDword(effectData + 0xC)
	local effectRES = IEex_ReadLString(effectData + 0x90, 8)
	local doDeflect = true
	if opcode ~= 12 then return false end
	if (damage_type == 0 and bit.band(types_blocked, 0x2000) > 0) or (damage_type ~= 0 and bit.band(types_blocked, damage_type) > 0) then
		if bit.band(savingthrow, 0x10000) == 0 and delay > 0 then
			IEex_IterateActorEffects(targetID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local thesavingthrow = IEex_ReadDword(eData + 0x48)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				local thevvcresource = IEex_ReadLString(eData + 0x70, 8)
				if theopcode == 0 and bit.band(thesavingthrow, 0x100000) > 0 and theresource == parent_resource and thevvcresource == "MEDAMPRC" then
					doDeflect = false
				end
			end)
		end
		if doDeflect then
			if bit.band(savingthrow, 0x10000) > 0 and delay ~= -1 then
				if delay > 0 then
					delay = delay - 1
					IEex_WriteDword(originatingEffectData + 0x44, delay)
				else
					return false
				end
			end
			
			if bit.band(savingthrow, 0x10000) == 0 and delay > 0 then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 0,
["duration"] = delay,
["resource"] = parent_resource,
["vvcresource"] = "MEDAMPRC",
["parent_resource"] = "MEDEFDEL",
["savingthrow"] = 0x100000,
["internal_flags"] = 0x4000000,
["source_target"] = targetID,
["source_id"] = targetID,
})
			end
			IEex_WriteDword(effectData + 0x18, math.floor(damage - damage * percentageModifier / 100))
			IEex_WriteDword(effectData + 0x34, math.floor(dicenumber - dicenumber * percentageModifier / 100))
			if bit.band(savingthrow, 0x10000) > 0 and bit.band(savingthrow, 0x20000) > 0 and delay == 0 then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["duration"] = IEex_GetGameTick() + 1,
["resource"] = parent_resource,
["internal_flags"] = 0x4000000,
["source_target"] = targetID,
["source_id"] = targetID
})
			end
			if percentageModifier >= 100 then return true end
		end
	end
	return false
end

function MEDAMSLV(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, true) then return false end
	local sourceData = IEex_GetActorShare(sourceID)
	local modifier = IEex_ReadDword(originatingEffectData + 0x18)
	local reductionType = IEex_ReadWord(originatingEffectData + 0x1C, 0x0)
	local maxEnchantment = IEex_ReadWord(originatingEffectData + 0x1E, 0x0)
	local savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
	local string = IEex_ReadDword(originatingEffectData + 0x44)
	local parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
	local damage = IEex_ReadDword(effectData + 0x18)
	local damage_type = IEex_ReadWord(effectData + 0x1E, 0x0)
	local dicenumber = IEex_ReadDword(effectData + 0x34)
	local flags = IEex_ReadDword(effectData + 0x44)
	local restype = IEex_ReadDword(effectData + 0x8C)
	local internal_flags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if bit.band(internal_flags, 0x4000000) > 0 then return false end
	local opcode = IEex_ReadDword(effectData + 0xC)
	if opcode ~= 12 or IEex_ReadLString(effectData + 0x90, 8) ~= "IEEX_DAM" then return false end
	if damage <= 0 and dicenumber <= 0 then return false end
	local doDeflect = false
	local weaponRES = IEex_ReadLString(effectData + 0x6C, 8)
	local resWrapper = IEex_DemandRes(weaponRES, "ITM")
	local weaponData = 0
	if resWrapper:isValid() then
		weaponData = resWrapper:getData()
	else
		resWrapper:free()
		return false
	end
	local currentHeader = IEex_ReadSignedWord(sourceData + 0x4BA6, 0x0)
	local numHeaders = IEex_ReadWord(weaponData + 0x68, 0x0)
	if currentHeader >= numHeaders then
		currentHeader = numHeaders - 1
	end
	local headerType = IEex_ReadByte(weaponData + 0x82 + 0x38 * currentHeader, 0x0)
	local weaponFlags = IEex_ReadDword(weaponData + 0x18)
	local weaponType = IEex_ReadWord(weaponData + 0x1C, 0x0)
	local weaponEnchantment = IEex_ReadDword(weaponData + 0x60)
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theweaponRES = IEex_ReadLString(eData + 0x1C, 8)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local theresource = IEex_ReadLString(eData + 0x30, 8)
		local thespecial = IEex_ReadDword(eData + 0x48)
		if theopcode == 500 and theresource == "MEWEPFLG" and (theweaponRES == "" or theweaponRES == weaponRES) and (bit.band(thesavingthrow, 0x20000000) == 0 or thespecial == -1 or thespecial == weaponType) and (bit.band(thesavingthrow, 0x20000000) > 0 or thespecial == 0 or thespecial == headerType) then
			if bit.band(thesavingthrow, 0x10000000) == 0 then
				weaponFlags = bit.bor(weaponFlags, thesavingthrow)
			else
				thesavingthrow = bit.band(thesavingthrow, 0xEFFFFFFF)
				local effectOffset = IEex_ReadDword(weaponData + 0x6A)
				local numGlobalEffects = IEex_ReadWord(weaponData + 0x70, 0x0)
				local numHeaderEffects = IEex_ReadWord(weaponData + 0x82 + currentHeader * 0x38 + 0x1E, 0x0)
				local headerFirstEffectIndex = IEex_ReadWord(weaponData + 0x82 + currentHeader * 0x38 + 0x20, 0x0)
				for i = 0, numHeaderEffects - 1, 1 do
					local offset = weaponData + effectOffset + (headerFirstEffectIndex + i) * 0x30
					if IEex_ReadWord(offset, 0x0) == 500 and IEex_ReadLString(offset + 0x14, 8) == "MEEXHIT" and IEex_ReadDword(offset + 0x8) == 2001 then
						weaponFlags = bit.bor(weaponFlags, thesavingthrow)
					end
				end
			end
		end
	end)
	if (reductionType == 1 and bit.band(weaponFlags, 0x40) > 0) or (reductionType == 2 and bit.band(weaponFlags, 0x40) == 0) or (reductionType == 3 and bit.band(weaponFlags, 0x100) > 0) or (reductionType == 4 and bit.band(weaponFlags, 0x100) == 0) or (reductionType == 5 and bit.band(weaponFlags, 0x140) == 0) or (reductionType == 6 and bit.band(weaponFlags, 0x2) > 0) or (reductionType == 7 and bit.band(weaponFlags, 0x2) == 0) or (reductionType == 8 and bit.band(weaponFlags, 0x10) > 0) or (reductionType == 9 and bit.band(weaponFlags, 0x10) == 0) or (reductionType == 10 and bit.band(weaponFlags, 0x200) > 0) or (reductionType == 11 and bit.band(weaponFlags, 0x200) == 0) or (reductionType == 12 and bit.band(weaponFlags, 0x10000) > 0) or (reductionType == 13 and bit.band(weaponFlags, 0x10000) == 0) or (reductionType == 14 and bit.band(weaponFlags, 0x20000) > 0) or (reductionType == 15 and bit.band(weaponFlags, 0x20000) == 0) or (reductionType == 16 and bit.band(weaponFlags, 0x40000) > 0) or (reductionType == 17 and bit.band(weaponFlags, 0x40000) == 0) or (reductionType == 18 and bit.band(weaponFlags, 0x80000) > 0) or (reductionType == 19 and bit.band(weaponFlags, 0x80000) == 0) or (reductionType == 20 and bit.band(weaponFlags, 0x10100) == 0) or (reductionType == 21 and bit.band(weaponFlags, 0x10200) == 0) or (reductionType == 22 and (bit.band(weaponFlags, 0x10000) == 0 or (damage_type ~= 0x10 and damage_type ~= 0x200))) or (reductionType == 23 and bit.band(weaponFlags, 0x90100) == 0) or (reductionType == 24 and bit.band(weaponFlags, 0x50200) == 0) or (reductionType == 25 and bit.band(weaponFlags, 0xA0000) == 0) then
		doDeflect = true
	end
	resWrapper:free()
	if reductionType == 0 and weaponEnchantment <= maxEnchantment then
		doDeflect = true
	end
	if doDeflect then
		if string > 0 then
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = string,
["resource"] = parent_resource,
["parent_resource"] = "MEDEFSTR",
["internal_flags"] = 0x4000000,
["source_target"] = targetID,
["source_id"] = targetID,
})
		end
		if bit.band(savingthrow, 0x10000) == 0 then
			damage = damage - modifier
		else
			damage = math.floor(damage - damage * modifier / 100)
		end
		if damage < 0 then 
			damage = 0
		end
		IEex_WriteDword(effectData + 0x18, damage)

	end
	return false
end

function MEREBOUN(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local percentage = IEex_ReadDword(originatingEffectData + 0x18)
	local types_blocked = IEex_ReadDword(originatingEffectData + 0x1C)
	local savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
	local delay = IEex_ReadDword(originatingEffectData + 0x44)
	local parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
	local damage = IEex_ReadDword(effectData + 0x18)
	local damage_type = IEex_ReadWord(effectData + 0x1E, 0x0)
	local flags = IEex_ReadDword(effectData + 0x44)
	local restype = IEex_ReadDword(effectData + 0x8C)
	local internal_flags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if bit.band(internal_flags, 0x4000000) > 0 then return false end
	local opcode = IEex_ReadDword(effectData + 0xC)
	local effectRES = IEex_ReadLString(effectData + 0x90, 8)
	local doDeflect = true
	if opcode ~= 12 then return false end
	if bit.band(savingthrow, 0x10000) == 0 and IEex_GetActorSpellState(targetID, 246) then
		IEex_IterateActorEffects(targetID, function(eData)
			local the_opcode = IEex_ReadDword(eData + 0x10)
			local the_parameter1 = IEex_ReadDword(eData + 0x1C)
			local the_parameter2 = IEex_ReadDword(eData + 0x20)
			local the_special = IEex_ReadDword(eData + 0x48)
			local the_resource = IEex_ReadLString(eData + 0x30, 8)
			if the_opcode == 288 and the_parameter1 > 0 and the_parameter2 == 246 and the_resource == parent_resource then
				doDeflect = false
			end
		end)
	end
	if (damage_type == 0 and bit.band(types_blocked, 0x4000) > 0) or (damage_type ~= 0 and bit.band(types_blocked, damage_type) > 0) then
		if doDeflect then
			if bit.band(savingthrow, 0x10000) > 0 and delay ~= -1 then
				if delay > 0 then
					delay = delay - 1
					IEex_WriteDword(originatingEffectData + 0x44, delay)
				else
					return false
				end
			end
			
			if bit.band(savingthrow, 0x10000) == 0 and delay ~= -1 then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = delay,
["parameter1"] = 1,
["parameter2"] = 246,
["resource"] = parent_resource,
["parent_resource"] = "MEREBDEL",
["internal_flags"] = 0x4000000,
["source_target"] = targetID,
["source_id"] = targetID,
})
			end
			damage = math.floor(damage * percentage / 100)
			if bit.band(savingthrow, 0x100000) > 0 and IEex_IsSprite(sourceID, false) and targetID ~= sourceID then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = IEex_ReadDword(effectData + 0xC),
["target"] = IEex_ReadDword(effectData + 0x10),
["power"] = IEex_ReadDword(effectData + 0x14),
["parameter1"] = damage,
["parameter2"] = IEex_ReadDword(effectData + 0x1C),
["timing"] = IEex_ReadDword(effectData + 0x20),
["duration"] = IEex_ReadDword(effectData + 0x24),
["resource"] = IEex_ReadLString(effectData + 0x2C, 8),
["dicenumber"] = IEex_ReadDword(effectData + 0x34),
["dicesize"] = IEex_ReadDword(effectData + 0x38),
["savingthrow"] = IEex_ReadDword(effectData + 0x3C),
["savebonus"] = IEex_ReadDword(effectData + 0x40),
["special"] = IEex_ReadDword(effectData + 0x44),
["school"] = IEex_ReadDword(effectData + 0x48),
["resist_dispel"] = IEex_ReadDword(effectData + 0x58),
["parameter3"] = IEex_ReadDword(effectData + 0x5C),
["parameter4"] = IEex_ReadDword(effectData + 0x60),
["parameter5"] = IEex_ReadDword(effectData + 0x64),
["vvcresource"] = IEex_ReadLString(effectData + 0x6C, 8),
["resource2"] = IEex_ReadLString(effectData + 0x74, 8),
["source_x"] = IEex_ReadDword(creatureData + 0x8),
["source_y"] = IEex_ReadDword(creatureData + 0xC),
["target_x"] = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0x8),
["target_y"] = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0xC),
["restype"] = IEex_ReadDword(effectData + 0x8C),
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["resource_flags"] = IEex_ReadDword(effectData + 0x98),
["impact_projectile"] = IEex_ReadDword(effectData + 0x9C),
["sourceslot"] = IEex_ReadDword(effectData + 0xA0),
["effvar"] = IEex_ReadLString(effectData + 0xA4, 32),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = bit.bor(internal_flags, 0x4000000),
["sectype"] = IEex_ReadDword(effectData + 0x4C),
["source_target"] = sourceID,
["source_id"] = targetID
})
			end
			if bit.band(savingthrow, 0x10000) > 0 and bit.band(savingthrow, 0x20000) > 0 and delay == 0 then
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["duration"] = IEex_GetGameTick() + 1,
["resource"] = parent_resource,
["internal_flags"] = 0x4000000,
["source_target"] = targetID,
["source_id"] = targetID
})
			end
		end
	end
	return false
end

function MEARCAEV(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local resource = IEex_ReadLString(effectData + 0x2C, 8)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local school = IEex_ReadDword(effectData + 0x48)
	if opcode == 500 and resource == "EXDAMAGE" and bit.band(savingthrow, 0x1C00) == 0 and (school == 2 or school == 6) then
		savingthrow = bit.bor(savingthrow, 0x800)
		IEex_WriteDword(effectData + 0x3C, savingthrow)
	end
	return false
end

function MESANCTU(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, true) then return false end
	if IEex_GetActorSpellState(targetID, 189) and not IEex_GetActorSpellState(sourceID, 189) and IEex_ReadDword(effectData + 0x14) ~= 10 then return true end
	return false
end

function MEKAERVA(originatingEffectData, effectData, creatureData)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local internal_flags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if opcode == 12 and bit.band(internal_flags, 0x4000000) > 0 then
		local damage = IEex_ReadDword(effectData + 0x18)
		IEex_WriteDword(effectData + 0x18, damage * 3)
		IEex_WriteDword(effectData + 0x1C, 0)
	end
	return false
end

function MEDEATYP(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local o_sourceID = IEex_ReadDword(originatingEffectData + 0x10C)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local numResurrections = IEex_ReadDword(originatingEffectData + 0x18)
	local o_timing = IEex_ReadDword(originatingEffectData + 0x20)
	local o_parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local durationEnd = IEex_ReadDword(originatingEffectData + 0x68) + IEex_ReadDword(originatingEffectData + 0x44) * 15 + 2
	local o_savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
	if IEex_GetGameTick() <= durationEnd or IEex_ReadDword(originatingEffectData + 0x44) == -1 then
		if opcode == 13 or opcode == 420 then
			IEex_WriteDword(effectData + 0x1C, IEex_ReadDword(originatingEffectData + 0x1C))
			if bit.band(o_savingthrow, 0x10000) > 0 then
				IEex_WriteDword(effectData + 0x18, 1)
			end
			if bit.band(o_savingthrow, 0x10000000) > 0 then
				local extraFlags = IEex_ReadDword(creatureData + 0x740)
				extraFlags = bit.bor(extraFlags, 0x10000000)
				IEex_WriteDword(creatureData + 0x740, extraFlags)
			end
			if bit.band(o_savingthrow, 0x20000000) > 0 then
				local extraFlags = IEex_ReadDword(creatureData + 0x740)
				extraFlags = bit.bor(extraFlags, 0x20000000)
				IEex_WriteDword(creatureData + 0x740, extraFlags)
			end
			if IEex_IsPartyMember(targetID) and bit.band(o_savingthrow, 0x8000000) > 0 then
				if bit.band(o_savingthrow, 0x20000000) > 0 then
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55378,
["source_target"] = targetID,
["source_id"] = targetID
})
				elseif bit.band(o_savingthrow, 0x10000000) > 0 then
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55377,
["source_target"] = targetID,
["source_id"] = targetID
})
				end
			end
		end
	else
		IEex_WriteDword(originatingEffectData + 0x110, 1)
	end
end

ex_soul_bind_gems = {["00GEM28"] = "USGEM28S", ["00GEM29"] = "USGEM29S", ["00GEM30"] = "USGEM30S", }

function MESOULBI(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local o_sourceID = IEex_ReadDword(originatingEffectData + 0x10C)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local o_parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local durationEnd = IEex_ReadDword(originatingEffectData + 0x68) + IEex_ReadDword(originatingEffectData + 0x44) * 15 + 2
	local o_savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
	local constantID = IEex_ReadDword(creatureData + 0x700)
	local sourceData = IEex_GetActorShare(o_sourceID)
	if sourceData <= 0 then return false end
	if IEex_GetGameTick() <= durationEnd or IEex_ReadDword(originatingEffectData + 0x44) == -1 then
		if opcode == 13 or opcode == 420 then
			local foundGem = false
			for i = 15, 41, 1 do
				if not foundGem then
					local slotData = IEex_ReadDword(sourceData + 0x4AD8 + i * 0x4)
					if slotData > 0 then
						local soulGemRES = ex_soul_bind_gems[IEex_ReadLString(slotData + 0xC, 8)]
						if soulGemRES ~= nil then
							foundGem = true
							IEex_WriteDword(originatingEffectData + 0x110, 1)
							local numGems = IEex_ReadWord(slotData + 0x18, 0x0)
							if numGems <= 1 then
								IEex_ApplyEffectToActor(o_sourceID, {
["opcode"] = 143,
["target"] = 2,
["timing"] = 1,
["parameter1"] = i,
["resource"] = soulGemRES,
["source_id"] = o_sourceID
})
								slotData = IEex_ReadDword(sourceData + 0x4AD8 + i * 0x4)
								if slotData > 0 then
									IEex_WriteWord(slotData + 0x18, 1)
									IEex_WriteDword(slotData + 0x1A, constantID)
								end
							else
								IEex_WriteWord(slotData + 0x18, numGems - 1)
								IEex_ApplyEffectToActor(o_sourceID, {
["opcode"] = 122,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 1,
["resource"] = soulGemRES,
["source_id"] = o_sourceID
})
								for j = 15, 41, 1 do
									local slotDataB = IEex_ReadDword(sourceData + 0x4AD8 + j * 0x4)
									if slotDataB > 0 then
										if IEex_ReadLString(slotDataB + 0xC, 8) == soulGemRES and IEex_ReadDword(slotDataB + 0x1A) == 0 then
											IEex_WriteDword(slotDataB + 0x1A, constantID)
										end
									end
								end
							end
							IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 9,
["parameter2"] = 102,
["source_id"] = o_sourceID
})
							IEex_ApplyEffectToActor(o_sourceID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 9,
["parameter2"] = 103,
["source_id"] = o_sourceID
})
							local extraFlags = IEex_ReadDword(creatureData + 0x740)
							IEex_WriteDword(creatureData + 0x740, bit.bor(extraFlags, 0x30000000))
						end
					end
				end
			end
		end
	else
		IEex_WriteDword(originatingEffectData + 0x110, 1)
	end
end

function MESOULB2(actionData, creatureData)
--	if true then return false end
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	local slot = IEex_GetActionInt1(actionData)
	if actionID == 34 and slot >= 15 and slot <= 17 then
		local slotData = IEex_ReadDword(creatureData + 0x4AD8 + slot * 0x4)
		if slotData > 0 then
			local soulGemRES = IEex_ReadLString(slotData + 0xC, 8)
			local isSoulGem = false
			for k, v in pairs(ex_soul_bind_gems) do
				if v == soulGemRES then
					isSoulGem = true
				end
			end
			if isSoulGem then
				local soulConstantID = IEex_ReadDword(slotData + 0x1A)
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USSOULID",
["parent_resource"] = "USSOULID",
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 0,
["duration"] = 20,
["parameter3"] = soulConstantID,
["parent_resource"] = "USSOULID",
["source_id"] = sourceID
})
			end
		end
	end
end

IEex_AddActionHookGlobal("MESOULB2")

function MERESCON(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local o_sourceID = IEex_ReadDword(originatingEffectData + 0x10C)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local numResurrections = IEex_ReadDword(originatingEffectData + 0x18)
	local o_timing = IEex_ReadDword(originatingEffectData + 0x20)
	local o_parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local resurrectionEnd = IEex_ReadDword(originatingEffectData + 0x68) + IEex_ReadDword(originatingEffectData + 0x44) * 15
	local o_savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
	if IEex_GetGameTick() <= resurrectionEnd or IEex_ReadDword(originatingEffectData + 0x44) == 0 or bit.band(o_savingthrow, 0x40000) > 0 then
		if opcode == 13 or opcode == 420 then
			local doResurrect = false
			if o_timing == 2 then
				for i = 0, 50, 1 do
					if not doResurrect and (i <= 14 or i >= 42) then
						local slotData = IEex_ReadDword(creatureData + 0x4AD8 + i * 0x4)
						if slotData > 0 then
							if IEex_ReadLString(slotData + 0xC, 8) == o_parent_resource then
								local charges1 = IEex_ReadWord(slotData + 0x18, 0x0)
								if charges1 >= 1 or numResurrections == -1 then
									doResurrect = true
									if charges1 ~= 32767 and charges >= 1 then
										charges1 = charges1 - 1
										IEex_WriteWord(slotData + 0x18, charges1)
									end
								end
							end
						end
					end
				end
			else
				if numResurrections ~= 0 then
					doResurrect = true
					if numResurrections > 0 then
						numResurrections = numResurrections - 1
						IEex_WriteDword(originatingEffectData + 0x18, numResurrections)
					end
				end
			end
			if numResurrections == 0 and o_timing ~= 2 then
				IEex_WriteDword(originatingEffectData + 0x110, 1)
			end
			if doResurrect then
				if bit.band(o_savingthrow, 0x40000) == 0 then
					if bit.band(o_savingthrow, 0x10000) == 0 then
						IEex_WriteWord(creatureData + 0x5C0, IEex_GetActorStat(targetID, 1))
					else
						IEex_WriteWord(creatureData + 0x5C0, 1)
					end
					if bit.band(o_savingthrow, 0x20000) == 0 then
						IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 9,
["parameter2"] = 54,
["source_target"] = targetID,
["source_id"] = targetID
})
					else
						IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 9,
["resource"] = o_parent_resource .. "R",
["parent_resource"] = o_parent_resource .. "R",
["source_target"] = targetID,
["source_id"] = o_sourceID
})
					end
				else
--[[
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
["resist_dispel"] = 2,
["special"] = IEex_ReadDword(originatingEffectData + 0x44),
["resource"] = "MERESCOD",
["parent_resource"] = o_parent_resource .. "R",
["source_target"] = targetID,
["source_id"] = o_sourceID
})
--]]
				end
				if numResurrections == 0 and o_timing ~= 2 then
					IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = o_parent_resource,
["source_target"] = targetID,
["source_id"] = targetID
})
				end
				if doResurrect and bit.band(o_savingthrow, 0x40000) == 0 then
					return true
				else
					return false
				end
			end
		end
	elseif IEex_ReadLString(originatingEffectData + 0x2C, 8) == "MERESCON" then
		IEex_WriteDword(originatingEffectData + 0x110, 1)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = o_parent_resource,
["source_target"] = targetID,
["source_id"] = targetID
})
	end
end

function MERESCOD(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	if IEex_IsSprite(sourceID, false) then return end
	local timeOfDeath = IEex_ReadDword(creatureData + 0x704)
	if timeOfDeath <= 0 then return end
	local timeOfRevival = timeOfDeath + IEex_ReadDword(effectData + 0x44) * 15
	if IEex_GetGameTick() >= timeOfRevival then
		IEex_WriteDword(effectData + 0x110, 1)
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 9,
--["resist_dispel"] = 2,
["savingthrow"] = 0x20000,
["resource"] = "MERAISED",
["source_target"] = sourceID,
["source_id"] = sourceID
})
	end
end

function MEFOOLSM(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, true) then return end
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local stat = IEex_ReadDword(effectData + 0x44)
	local sourceStat = IEex_GetActorStat(sourceID, stat)
	local targetStat = IEex_GetActorStat(targetID, stat)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	if bit.band(savingthrow, 0x10000) > 0 then
		sourceStat = math.floor((sourceStat - 10) / 2)
		targetStat = math.floor((targetStat - 10) / 2)
	end
	if sourceStat > targetStat then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 1,
["parameter1"] = sourceStat - targetStat,
["parameter2"] = parameter2,
["savingthrow"] = 0x10000,
["resource"] = "EXDAMAGE",
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
	elseif targetStat > sourceStat then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 1,
["parameter1"] = targetStat - sourceStat,
["parameter2"] = parameter2,
["savingthrow"] = 0x10000,
["resource"] = "EXDAMAGE",
["parent_resource"] = parent_resource,
["source_id"] = sourceID
})
	end
end

function MEPRTLEV(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local o_sourceID = IEex_ReadDword(originatingEffectData + 0x10C)
	local power = IEex_ReadDword(effectData + 0x14)
	local minLevel = IEex_ReadDword(originatingEffectData + 0x18)
	local maxLevel = IEex_ReadDword(originatingEffectData + 0x20)
	local o_savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
	local selfSpellStillWorks = (bit.band(o_savingthrow, 0x10000) > 0)
	local alliedSpellStillWorks = (bit.band(o_savingthrow, 0x20000) > 0)
	if power >= minLevel and power <= maxLevel and (not selfSpellStillWorks or targetID ~= sourceID) and (not alliedSpellStillWorks or IEex_CompareActorAllegiances(targetID, sourceID) ~= 1) then
		return true
	end
	return false
end

IEex_AddScreenEffectsGlobal("MEQUABIL", function(effectData, creatureData)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local timing = IEex_ReadDword(effectData + 0x20)
	if opcode == 171 and (timing <= 1 or timing >= 9) then
		local resource = IEex_ReadLString(effectData + 0x2C, 8)
		for i = 0, 8, 1 do
			local offset = creatureData + 0x38DC + 0x3C * i
			if IEex_ReadLString(offset + 0x20, 8) == resource then
				local count = IEex_ReadSignedWord(offset + 0x18, 0x0)
				if count >= 0 then
					IEex_WriteWord(offset + 0x18, count + 1)
					IEex_WriteByte(offset + 0x3A, 0)
				end
			end
		end
	end
end)

IEex_AddScreenEffectsGlobal("MERESTRE", function(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	if opcode == 17 and parameter1 == 1 and parameter2 == 0 and parent_resource == "" and sourceID == -1 then
		IEex_WriteDword(effectData + 0x18, IEex_GetActorStat(targetID, 95))
	end
end)

IEex_AddScreenEffectsGlobal("MEETHERE", function(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, true) then return false end
	local internalFlags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	local targetGhostState = 0
	local sourceGhostState = 0
	if IEex_GetActorSpellState(targetID, 182) then
		targetGhostState = 2
	elseif IEex_GetActorSpellState(targetID, 189) then
		targetGhostState = 1
	end
	if (IEex_GetActorSpellState(sourceID, 182) and bit.band(internalFlags, 0x20) == 0) or bit.band(internalFlags, 0x420) == 0x420 then
		sourceGhostState = 2
	elseif IEex_GetActorSpellState(sourceID, 189) then
		sourceGhostState = 1
	end
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	if parent_resource == "IEEX_DAM" then
		if ex_ethereal_sources[IEex_ReadLString(effectData + 0x6C, 8)] ~= nil or ex_ethereal_sources[IEex_ReadLString(effectData + 0x74, 8)] ~= nil then return false end
	elseif ex_ethereal_sources[parent_resource] ~= nil then 
		return false
	end
	if IEex_ReadDword(effectData + 0x14) == 10 then return false end
	if targetGhostState - sourceGhostState == 1 then
		local opcode = IEex_ReadDword(effectData + 0xC)
		local damageType = IEex_ReadWord(effectData + 0x1E, 0x0)
		if opcode == 12 and (damageType == 0 or bit.band(damageType, 0xF90) > 0) then
			if math.random(100) <= 50 then 
				IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 1,
["parameter1"] = ex_tra_55385,
["source_id"] = targetID
})
				return true
			end
		end
	elseif math.abs(targetGhostState - sourceGhostState) == 2 then
		return true
	end
	return false
end)

me_portrait_0_xp = 0
IEex_AddScreenEffectsGlobal("MEXPBALA", function(effectData, creatureData)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	if opcode == 104 and parameter2 == 0 then
		local targetID = IEex_GetActorIDShare(creatureData)
		local parameter1 = IEex_ReadDword(effectData + 0x18)
		if targetID == IEex_GetActorIDPortrait(0) then
			me_portrait_0_xp = parameter1
		elseif parameter1 == me_portrait_0_xp - 1 then
			parameter1 = me_portrait_0_xp
			IEex_WriteDword(effectData + 0x18, parameter1)
		end
	end
end)

IEex_AddScreenEffectsGlobal("METELGWK", function(effectData, creatureData)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	if opcode == 124 and parameter2 == 0 then
		local targetX = IEex_ReadDword(effectData + 0x84)
		local targetY = IEex_ReadDword(effectData + 0x88)
		local targetID = IEex_GetActorIDShare(creatureData)
		if ex_ghostwalk_dest["" .. targetID] ~= nil then
			ex_ghostwalk_dest["" .. targetID] = {targetX, targetY}
		end
		local areaData = IEex_ReadDword(creatureData + 0x12)
		if areaData <= 0 then return false end
		local areaRES = IEex_ReadLString(areaData, 8)
		local destinationHeight = 0
		if ex_specific_floor_height[areaRES] ~= nil then
			local heightMap2Wrapper = IEex_DemandRes(areaRES .. "H2", "BMP")
			if heightMap2Wrapper:isValid() then
				local heightMap2Data = heightMap2Wrapper:getData()
				local specificFloorHeight = IEex_GetBitmapPixelColor(heightMap2Data, math.floor(targetX / 16), math.floor(targetY / 12))

				if ex_specific_floor_height[areaRES][specificFloorHeight] ~= nil then
					destinationHeight = ex_specific_floor_height[areaRES][specificFloorHeight]
				end
			end
			heightMap2Wrapper:free()
		end
		local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
		if destinationHeight < 0 then
			IEex_WriteByte(creatureData + 0x9DC, 1)
			IEex_ApplyEffectToActor(targetID, {
["opcode"] = 184,
["target"] = 2,
["timing"] = 0,
["parameter2"] = 1,
["source_id"] = targetID
})
		end
	end
	if opcode == 124 then
		IEex_PreventMovingAttacksOfOpportunity(IEex_GetActorIDShare(creatureData), 10)
	end
end)

function MELINKST(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 0x1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(targetID, false) or not IEex_IsSprite(sourceID, false) or targetID == sourceID then return false end
	local linkRES = IEex_ReadLString(effectData + 0x18, 8)
	local timing = IEex_ReadDword(effectData + 0x20)
	local duration = IEex_ReadDword(effectData + 0x24)
	if timing == 4096 then
		timing = 0
		duration = math.floor((duration - IEex_GetGameTick()) / 15)
	end
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local special = IEex_ReadDword(effectData + 0x44)
	local re = IEex_ReadDword(effectData + 0x44)
	local linkNumber = math.random(0x40000000)
	if bit.band(savingthrow, 0x10000) > 0 or bit.band(savingthrow, 0x20000) == 0 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = linkRES,
["internal_flags"] = 0x4000001,
["source_target"] = targetID,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter2"] = 209,
["parameter3"] = linkNumber,
["resource"] = linkRES,
["internal_flags"] = 0x4000001,
["source_target"] = sourceID,
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 502,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["resist_dispel"] = IEex_ReadDword(effectData + 0x58),
["parameter3"] = linkNumber,
["special"] = IEex_ReadDword(effectData + 0x44),
["resource"] = linkRES,
["parent_resource"] = linkRES,
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = 0x4000001,
["source_target"] = targetID,
["source_id"] = sourceID
})
	end
	if bit.band(savingthrow, 0x20000) > 0 then
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = linkRES,
["internal_flags"] = 0x4000001,
["source_target"] = sourceID,
["source_id"] = targetID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter2"] = 209,
["parameter3"] = linkNumber,
["resource"] = linkRES,
["internal_flags"] = 0x4000001,
["source_target"] = targetID,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 502,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["resist_dispel"] = IEex_ReadDword(effectData + 0x58),
["parameter3"] = linkNumber,
["special"] = IEex_ReadDword(effectData + 0x44),
["resource"] = linkRES,
["parent_resource"] = linkRES,
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = 0x4000001,
["source_target"] = sourceID,
["source_id"] = targetID
})
	end
end

function MELINKSH(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local linkID = IEex_ReadDword(originatingEffectData + 0x10C)
	local linkNumber = IEex_ReadDword(originatingEffectData + 0x5C)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local damage = IEex_ReadDword(effectData + 0x18)
	local damageType = IEex_ReadWord(effectData + 0x1E, 0x0)
	local internal_flags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if opcode ~= 12 or damageType == 0x20 or bit.band(internal_flags, 0x4000000) > 0 then return false end
	if linkID <= 0 then
		IEex_IterateIDs(IEex_ReadDword(creatureData + 0x12), 0x31, function(areaActorID)
			if linkID <= 0 and areaActorID ~= targetID and IEex_GetActorSpellState(areaActorID, 209) then
				IEex_IterateActorEffects(areaActorID, function(eData)
					local theopcode = IEex_ReadDword(eData + 0x10)
					local theparameter2 = IEex_ReadDword(eData + 0x20)
					local theparameter3 = IEex_ReadDword(eData + 0x60)
					local theresource = IEex_ReadLString(eData + 0x30, 8)
					if theopcode == 288 and theparameter2 == 209 and theresource == "MELINKSH" and theparameter3 == linkNumber then
						linkID = areaActorID
						IEex_WriteDword(originatingEffectData + 0x10C, linkID)
					end
				end)
			end
		end)
	end
	if not IEex_IsSprite(linkID, false) then return false end
	local damagePercentage = IEex_ReadWord(originatingEffectData + 0x44, 0x0)
	if damagePercentage > 100 then
		damagePercentage = 100
	elseif damagePercentage == 0 then
		damagePercentage = 50
	end
	local maxDistance = IEex_ReadWord(originatingEffectData + 0x46, 0x0)
	local targetX, targetY = IEex_GetActorLocation(targetID)
	local linkX, linkY = IEex_GetActorLocation(linkID)
	if maxDistance ~= 0 and (IEex_GetDistance(targetX, targetY, linkX, linkY) > maxDistance or not IEex_CheckActorLOSObject(targetID, linkID)) then return false end
	local redirectedDamage = math.ceil(damage * damagePercentage / 100)
	if redirectedDamage <= 0 then return false end
	damage = damage - redirectedDamage
	IEex_WriteDword(effectData + 0x18, damage)
	IEex_ApplyEffectToActor(linkID, {
["opcode"] = IEex_ReadDword(effectData + 0xC),
["target"] = IEex_ReadDword(effectData + 0x10),
["power"] = IEex_ReadDword(effectData + 0x14),
["parameter1"] = redirectedDamage,
["parameter2"] = IEex_ReadDword(effectData + 0x1C),
["timing"] = IEex_ReadDword(effectData + 0x20),
["duration"] = IEex_ReadDword(effectData + 0x24),
["resource"] = IEex_ReadLString(effectData + 0x2C, 8),
["dicenumber"] = IEex_ReadDword(effectData + 0x34),
["dicesize"] = IEex_ReadDword(effectData + 0x38),
["savingthrow"] = IEex_ReadDword(effectData + 0x3C),
["savebonus"] = IEex_ReadDword(effectData + 0x40),
["special"] = IEex_ReadDword(effectData + 0x44),
["school"] = IEex_ReadDword(effectData + 0x48),
["sectype"] = IEex_ReadDword(effectData + 0x4C),
["resist_dispel"] = IEex_ReadDword(effectData + 0x58),
["parameter3"] = IEex_ReadDword(effectData + 0x5C),
["parameter4"] = IEex_ReadDword(effectData + 0x60),
["parameter5"] = IEex_ReadDword(effectData + 0x64),
["vvcresource"] = IEex_ReadLString(effectData + 0x6C, 8),
["resource2"] = IEex_ReadLString(effectData + 0x74, 8),
["source_x"] = IEex_ReadDword(creatureData + 0x8),
["source_y"] = IEex_ReadDword(creatureData + 0xC),
["target_x"] = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0x8),
["target_y"] = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0xC),
["restype"] = IEex_ReadDword(effectData + 0x8C),
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["resource_flags"] = IEex_ReadDword(effectData + 0x98),
["impact_projectile"] = IEex_ReadDword(effectData + 0x9C),
["sourceslot"] = IEex_ReadDword(effectData + 0xA0),
["effvar"] = IEex_ReadLString(effectData + 0xA4, 32),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = bit.bor(internal_flags, 0x4000000),
["source_target"] = linkID,
["source_id"] = sourceID
})
	if damage <= 0 then
		return true
	else
		return false
	end
end

function MELINKEF(originatingEffectData, effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local linkID = IEex_ReadDword(originatingEffectData + 0x10C)
	local linkNumber = IEex_ReadDword(originatingEffectData + 0x5C)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local timing = IEex_ReadDword(effectData + 0x20)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local internal_flags = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4))
	if timing == 2 or bit.band(internal_flags, 0x4000000) > 0 then return false end
	if linkID <= 0 then
		IEex_IterateIDs(IEex_ReadDword(creatureData + 0x12), 0x31, function(areaActorID)
			if linkID <= 0 and areaActorID ~= targetID and IEex_GetActorSpellState(areaActorID, 209) then
				IEex_IterateActorEffects(areaActorID, function(eData)
					local theopcode = IEex_ReadDword(eData + 0x10)
					local theparameter2 = IEex_ReadDword(eData + 0x20)
					local theparameter3 = IEex_ReadDword(eData + 0x60)
					local theresource = IEex_ReadLString(eData + 0x30, 8)
					if theopcode == 288 and theparameter2 == 209 and theresource == "MELINKEF" and theparameter3 == linkNumber then
						linkID = areaActorID
						IEex_WriteDword(originatingEffectData + 0x10C, linkID)
					end
				end)
			end
		end)
	end
	if not IEex_IsSprite(linkID, false) then return false end
	if (opcode == 402 or opcode == 430) and bit.band(savingthrow, 0x1C) == 0 then return false end
	local isSpell = false
	local itemCheckWrapper = IEex_DemandRes(parent_resource, "ITM")
	if itemCheckWrapper:isValid() then
		itemCheckWrapper:free()
		return false
	end
	itemCheckWrapper:free()
	local resWrapper = IEex_DemandRes(parent_resource, "SPL")
	if resWrapper:isValid() then
		local spellData = resWrapper:getData()
		local spellType = IEex_ReadWord(spellData + 0x1C, 0x0)
		if spellType == 1 or spellType == 2 then
			isSpell = true
		end
	end
	resWrapper:free()
	local prefix = IEex_ReadLString(effectData + 0x90, 4)
	if ex_not_linkable_spell_list[parent_resource] ~= nil or (not isSpell and ex_linkable_ability_list[parent_resource] == nil and ex_linkable_prefix_list[prefix] == nil) then return false end
	if ex_linkable_self_spell_list[parent_resource] ~= nil then
		sourceID = targetID
	end
	IEex_ApplyEffectToActor(linkID, {
["opcode"] = IEex_ReadDword(effectData + 0xC),
["target"] = IEex_ReadDword(effectData + 0x10),
["power"] = IEex_ReadDword(effectData + 0x14),
["parameter1"] = IEex_ReadDword(effectData + 0x18),
["parameter2"] = IEex_ReadDword(effectData + 0x1C),
["timing"] = IEex_ReadDword(effectData + 0x20),
["duration"] = IEex_ReadDword(effectData + 0x24),
["resource"] = IEex_ReadLString(effectData + 0x2C, 8),
["dicenumber"] = IEex_ReadDword(effectData + 0x34),
["dicesize"] = IEex_ReadDword(effectData + 0x38),
["savingthrow"] = IEex_ReadDword(effectData + 0x3C),
["savebonus"] = IEex_ReadDword(effectData + 0x40),
["special"] = IEex_ReadDword(effectData + 0x44),
["school"] = IEex_ReadDword(effectData + 0x48),
["sectype"] = IEex_ReadDword(effectData + 0x4C),
["resist_dispel"] = IEex_ReadDword(effectData + 0x58),
["parameter3"] = IEex_ReadDword(effectData + 0x5C),
["parameter4"] = IEex_ReadDword(effectData + 0x60),
["parameter5"] = IEex_ReadDword(effectData + 0x64),
["vvcresource"] = IEex_ReadLString(effectData + 0x6C, 8),
["resource2"] = IEex_ReadLString(effectData + 0x74, 8),
["source_x"] = IEex_ReadDword(creatureData + 0x8),
["source_y"] = IEex_ReadDword(creatureData + 0xC),
["target_x"] = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0x8),
["target_y"] = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0xC),
["restype"] = IEex_ReadDword(effectData + 0x8C),
["parent_resource"] = IEex_ReadLString(effectData + 0x90, 8),
["resource_flags"] = IEex_ReadDword(effectData + 0x98),
["impact_projectile"] = IEex_ReadDword(effectData + 0x9C),
["sourceslot"] = IEex_ReadDword(effectData + 0xA0),
["effvar"] = IEex_ReadLString(effectData + 0xA4, 32),
["casterlvl"] = IEex_ReadDword(effectData + 0xC4),
["internal_flags"] = bit.bor(bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)), 0x4000000),
["source_target"] = linkID,
["source_id"] = sourceID
})
	return false
end

function MEHIDEPS(originatingEffectData, actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	if actionID == 18 then
		IEex_SetActionID(actionData, 0)
		IEex_WriteByte(creatureData + 0x4C53, 3)
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 0,
["resource"] = "ACT_07",
["parent_resource"] = "USHIDEPS",
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 0,
["parameter1"] = 19944,
["parent_resource"] = "USHIDEPS",
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 20,
["target"] = 2,
["timing"] = 0,
["duration"] = 20,
["parent_resource"] = "USHIDEPS",
["source_id"] = sourceID
})
--[[
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = USHIDEPS,
["source_target"] = sourceID,
["source_id"] = sourceID
})
--]]
	end
end

IEex_AddActionHookOpcode("MEHIDEPS")

function MEBARCAS(originatingEffectData, actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	local savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
	local invertSchool = (bit.band(savingthrow, 0x10000) > 0)
	local invertClass = (bit.band(savingthrow, 0x20000) > 0)
	local matchSchool = IEex_ReadSignedWord(originatingEffectData + 0x44, 0x0)
	local matchClass = IEex_ReadSignedWord(originatingEffectData + 0x46, 0x0)
	if actionID == 31 or actionID == 95 or actionID == 113 or actionID == 114 or actionID == 181 or actionID == 191 or actionID == 192 then
		local spellRES = IEex_GetActorSpellRES(sourceID)
		local spellSchool = ex_trueschool[spellRES]
		local casterClass = IEex_ReadByte(creatureData + 0x530, 0x0)
		if spellSchool ~= nil then
			if (matchSchool <= 0 or (matchSchool == spellSchool and not invertSchool) or (matchSchool ~= spellSchool and invertSchool)) and (matchClass <= 0 or (matchClass == casterClass and not invertClass) or (matchClass ~= casterClass and invertClass)) then
				IEex_SetActionID(actionData, 0)
			end
		end
	end
end

IEex_AddActionHookOpcode("MEBARCAS")

function MESTOV1(originatingEffectData, actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(originatingEffectData + 0x18)
	if actionID == 114 and IEex_GetActorSpellRES(sourceID) == "USSTOV1" then
		local sourceX, sourceY = IEex_GetActorLocation(sourceID)
		sourceY = sourceY - 200
		if sourceY < 3 then
			IEex_SetActionID(actionData, 0)
			return
		end
		IEex_WriteDword(creatureData + 0x540, sourceX)
		IEex_WriteDword(creatureData + 0x544, sourceY)
	end
end

IEex_AddActionHookOpcode("MESTOV1")

function MESYMPAT(originatingEffectData, actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	if actionID == 22 and IEex_GetActorSpellState(sourceID, 123) then
		local sourceX = IEex_ReadDword(creatureData + 0x6)
		local sourceY = IEex_ReadDword(creatureData + 0xA)
		local ids = {}
		if IEex_ReadDword(creatureData + 0x12) > 0 then
			ids = IEex_GetIDArea(sourceID, 0x31)
		end
		local closestDistance = 0x7FFFFFFF
		local nearestTarget = nil
		for k, currentID in ipairs(ids) do
			local currentShare = IEex_GetActorShare(currentID)
			if currentShare > 0 then
				local currentX = IEex_ReadDword(currentShare + 0x6)
				local currentY = IEex_ReadDword(currentShare + 0xA)
				local currentDistance = IEex_GetDistance(sourceX, sourceY, currentX, currentY)
				local states = IEex_ReadDword(currentShare + 0x5BC)
				local general = IEex_ReadByte(currentShare + 0x25, 0x0)
				local cea = IEex_CompareActorAllegiances(sourceID, currentID)
				if general == 104 and currentDistance < closestDistance and cea ~= 1 and bit.band(states, 0x800) == 0 then
					nearestTarget = currentID
					closestDistance = currentDistance
				end
			end
		end
		if nearestTarget ~= nil then
			IEex_WriteDword(creatureData + 0x4BE, nearestTarget)
		else
			IEex_SetActionID(actionData, 0)
		end
	end
end

IEex_AddActionHookOpcode("MESYMPAT")

function MEHARPYW(originatingEffectData, actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	local harpyID = IEex_ReadDword(originatingEffectData + 0x10C)
--	local harpyX, harpyY = IEex_GetActorLocation(harpyID)
	local parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
	if IEex_GetActorSpellState(sourceID, 123) and IEex_IsSprite(harpyID, false) then
		IEex_SetActionID(actionData, 22)
		IEex_WriteDword(creatureData + 0x4BE, harpyID)
	else
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = parent_resource,
["source_id"] = sourceID
})
		IEex_SetActionID(actionData, 0)
	end
end

IEex_AddActionHookOpcode("MEHARPYW")

function METELMOA(originatingEffectData, actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	local savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
	local special = IEex_ReadDword(originatingEffectData + 0x44)
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
	local destinationX = IEex_ReadDword(creatureData + 0x556E)
	local destinationY = IEex_ReadDword(creatureData + 0x5572)
	local action = IEex_ReadWord(creatureData + 0x476, 0x0)
	local actionX = IEex_ReadDword(creatureData + 0x540)
	local actionY = IEex_ReadDword(creatureData + 0x544)
	local disableTeleport = false
	local isOutdoors = false
	local isNight = false
	local areaData = IEex_ReadDword(creatureData + 0x12)
	if areaData <= 0 then return end
	local areaType = IEex_ReadWord(areaData + 0x40, 0x0)
	local areaRES = IEex_ReadLString(areaData, 8)
	if bit.band(areaType, 0x1) > 0 then
		isOutdoors = true
	end
	if bit.band(areaType, 0x40) > 0 or IEex_IsNight() then
		isNight = true
	end
	if bit.band(areaType, 0x800) > 0 then
		disableTeleport = true
	else
--[[
		if areaRES == "AR4102" and ((targetX >= 400 and targetX <= 970 and targetY >= 1030 and targetY <= 1350) or (destinationX >= 400 and destinationX <= 970 and destinationY >= 1030 and destinationY <= 1350)) then
			disableTeleport = true
		end
--]]
		if ex_specific_teleport_zone[areaRES] ~= nil then
			local noTeleportMapWrapper = IEex_DemandRes(areaRES .. "NT", "BMP")
			if noTeleportMapWrapper:isValid() then
				local noTeleportMapData = noTeleportMapWrapper:getData()
				local currentZone = IEex_GetBitmapPixelIndex(noTeleportMapData, math.floor(targetX / 16), math.floor(targetY / 12))
				local destinationZone = IEex_GetBitmapPixelIndex(noTeleportMapData, math.floor(destinationX / 16), math.floor(destinationY / 12))
				if currentZone ~= destinationZone then
					disableTeleport = true
				end
			end
			noTeleportMapWrapper:free()
		end
	end
	if bit.band(savingthrow, 0x10000) > 0 then
		local lightMapWrapper = IEex_DemandRes(areaRES .. "LM", "BMP")
		if lightMapWrapper:isValid() then
			local lightMapData = lightMapWrapper:getData()
			local currentBrightness = math.floor(IEex_GetBitmapPixelColor(lightMapData, math.floor(targetX / 16), math.floor(targetY / 12)) / 0x10000)
			local destinationBrightness = math.floor(IEex_GetBitmapPixelColor(lightMapData, math.floor(destinationX / 16), math.floor(destinationY / 12)) / 0x10000)
			if not isOutdoors then
				currentBrightness = currentBrightness - 40
				destinationBrightness = destinationBrightness - 40
			elseif isNight then
				currentBrightness = currentBrightness - 80
				destinationBrightness = destinationBrightness - 80
			end
			if currentBrightness > ex_shadowstep_brightness_max or destinationBrightness > ex_shadowstep_brightness_max then
				disableTeleport = true
			end
			lightMapWrapper:free()
		end
	end
	if disableTeleport == false and not IEex_IsGamePaused() then
		if action == 23 and (actionX > 0 and actionY > 0 and actionX < 10000 and actionY < 10000) then
			if special == 1 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 59,
["parent_resource"] = "USTELMOV",
["source_id"] = sourceID
})
			end
--			IEex_SetActionID(actionData, 0)
			local newDirection = IEex_GetActorRequiredDirection(sourceID, actionX, actionY)
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 124,
["target"] = 2,
["timing"] = 1,
["source_x"] = targetX,
["source_y"] = targetY,
["target_x"] = actionX,
["target_y"] = actionY,
["parent_resource"] = "USTELMOV",
["source_id"] = sourceID
})

			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = newDirection,
["resource"] = "MEFACE",
["parent_resource"] = "USTELMOV",
["source_id"] = sourceID
})

--			IEex_WriteByte(creatureData + 0x537E, newDirection)
--			IEex_WriteByte(creatureData + 0x5380, (newDirection + 1) % 16)
			if special == 1 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 1,
["parameter2"] = 60,
["parent_resource"] = "USTELMOV",
["source_id"] = sourceID
})
			end

		else
--[[
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 0,
["parent_resource"] = "USTELMOV",
["source_id"] = sourceID
})
--]]
		end
	end
end

IEex_AddActionHookOpcode("METELMOA")

function MEFACE(effectData, creatureData)
	local parameter1 = IEex_ReadDword(effectData + 0x18)
	IEex_WriteWord(creatureData + 0x537C, 0)
	IEex_WriteByte(creatureData + 0x537E, (parameter1 + 1) % 16)
	IEex_WriteByte(creatureData + 0x5380, parameter1)
end
ex_spell_no_dec_opcode_list = {}
ex_really_force_spell_opcode_list = {}
ex_really_force_spell_opcode_tick = {}
IEex_AddScreenEffectsGlobal("MEFORCND", function(effectData, creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local opcode = IEex_ReadDword(effectData + 0xC)
	local parameter2 = IEex_ReadDword(effectData + 0x1C)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if (opcode == 146 or opcode == 148) then
		if bit.band(savingthrow, 0x10000) > 0 then
			if ex_spell_no_dec_opcode_list[sourceID] == nil then
				ex_spell_no_dec_opcode_list[sourceID] = {IEex_ReadLString(effectData + 0x2C, 8)}
			else
				table.insert(ex_spell_no_dec_opcode_list[sourceID], IEex_ReadLString(effectData + 0x2C, 8))
			end
		end
		if parameter2 == 1 then
			if ex_really_force_spell_opcode_list[sourceID] == nil then
				ex_really_force_spell_opcode_list[sourceID] = {IEex_ReadLString(effectData + 0x2C, 8)}
			else
				table.insert(ex_really_force_spell_opcode_list[sourceID], IEex_ReadLString(effectData + 0x2C, 8))
			end
		end
	end
end)

function EXFORCDI(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	if actionID == 113 or actionID == 114 then
		local spellRES = IEex_GetActorSpellRES(sourceID)
		local targetID = IEex_GetActionObjectID(actionData)
		local targetX = IEex_GetActionPointX(actionData)
		local targetY = IEex_GetActionPointY(actionData)
		local casterClass = IEex_ReadByte(creatureData + 0x530, 0x0)
		local highestClassLevel = 0
		local highestLevelClass = 0
		local classSpellLevel = 1
		if casterClass == 0 then
			for i = 1, 11, 1 do
				if IEex_GetActorStat(sourceID, 95 + i) > highestClassLevel and IEex_GetClassSpellLevel(sourceID, i, spellRES) > 0 then
					highestLevelClass = i
					highestClassLevel = IEex_GetActorStat(sourceID, 95 + i)
					classSpellLevel = IEex_GetClassSpellLevel(sourceID, i, spellRES)
				end
			end
			casterClass = highestLevelClass
		end
		if IEex_ReadDword(creatureData + 0x52C) == 0 then
			IEex_WriteByte(creatureData + 0x530, casterClass)
			IEex_WriteByte(creatureData + 0x534, classSpellLevel)
			IEex_WriteDword(creatureData + 0x52C, IEex_GetActorStat(sourceID, 95 + casterClass))
		end
		if ex_really_force_spell_opcode_list[sourceID] ~= nil then
			local removedFromList = false
			for k, v in ipairs(ex_really_force_spell_opcode_list[sourceID]) do
				if not removedFromList and v == spellRES then
					ex_really_force_spell_opcode_tick[sourceID] = IEex_GetGameTick()
					removedFromList = true
					table.remove(ex_really_force_spell_opcode_list[sourceID], k)
				end
			end 
		end
		if actionID == 113 then
			targetX, targetY = IEex_GetActorLocation(targetID)
			if ex_spell_no_dec_opcode_list[sourceID] ~= nil then
				local removedFromList = false
				for k, v in ipairs(ex_spell_no_dec_opcode_list[sourceID]) do
					if not removedFromList and v == spellRES then
						removedFromList = true
						table.remove(ex_spell_no_dec_opcode_list[sourceID], k)
						IEex_SetActionID(actionData, 191)
					end
				end 
			end
		elseif actionID == 114 then
			if ex_spell_no_dec_opcode_list[sourceID] ~= nil then
				local removedFromList = false
				for k, v in ipairs(ex_spell_no_dec_opcode_list[sourceID]) do
					if not removedFromList and v == spellRES then
						removedFromList = true
						table.remove(ex_spell_no_dec_opcode_list[sourceID], k)
						IEex_SetActionID(actionData, 192)
					end
				end 
			end
		end
		if (actionID == 113 and sourceID ~= targetID) or actionID == 114 then
			local newDirection = IEex_GetActorRequiredDirection(sourceID, targetX, targetY)

			IEex_WriteWord(creatureData + 0x537C, 0)
			IEex_WriteByte(creatureData + 0x537E, (newDirection + 1) % 16)
			IEex_WriteByte(creatureData + 0x5380, newDirection)
--[[
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = newDirection,
["resource"] = "MEFACE",
["parent_resource"] = "USFORCDI",
["source_id"] = sourceID
})
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 0,
["parent_resource"] = "USFORCDI",
["source_id"] = sourceID
})
--]]
		end
	end
end

IEex_AddActionHookGlobal("EXFORCDI")

function MEHIDDEN(actionData, creatureData)
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	if extraFlags > 0 then
		local isHidden = IEex_ReadByte(creatureData + 0x838, 0x0)
		local actionID = IEex_GetActionID(actionData)
		if bit.band(extraFlags, 0x2000) > 0 and isHidden then
			if actionID == 8 or IEex_InCutsceneMode() or IEex_IsDialogWindowOpen() then
				IEex_WriteDword(creatureData + 0x740, bit.band(extraFlags, 0xFFFFDFFF))
				IEex_WriteByte(creatureData + 0x838, 0)
			else
				IEex_SetActionID(actionData, 0)
			end
		end
	end
end

IEex_AddActionHookGlobal("MEHIDDEN")

function METSTOPA(actionData, creatureData)
	if ex_time_slow_speed_divisor == 0x7FFFFFFF then
		local targetID = IEex_GetActorIDShare(creatureData)
		local timeSlowed, targetNotSlowed = IEex_CheckGlobalEffectOnActor(targetID, 0x2)
		local actionID = IEex_GetActionID(actionData)
		if timeSlowed and not targetNotSlowed and actionID ~= 8 and not IEex_InCutsceneMode() and not IEex_IsDialogWindowOpen() then
			IEex_SetActionID(actionData, 0)
		end
	end
end

IEex_AddActionHookGlobal("METSTOPA")

function MENOTHIN(originatingEffectData, actionData, creatureData)
	IEex_WriteWord(creatureData + 0x476, 0)
end

IEex_AddActionHookOpcode("MENOTHIN")

function MENOINID(originatingEffectData, actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
	if actionID == 139 or ((actionID == 8 or actionID == 137 or actionID == 198) and bit.band(savingthrow, 0x10000) > 0) then
		IEex_WriteWord(creatureData + 0x476, 0)
	end
end

IEex_AddActionHookOpcode("MENOINID")

function MEEXPERT(actionData, creatureData)
	if IEex_ReadDword(creatureData + 0x4C54) > 0 then
		local targetID = IEex_GetActorIDShare(creatureData)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 0,
["duration"] = 0,
["parent_resource"] = "USEXPERT",
["source_id"] = targetID
})
	end
end

IEex_AddActionHookGlobal("MEEXPERT")

function MECLEARA(effectData, creatureData)
	IEex_WriteWord(creatureData + 0x476, 0)
end

ex_global_effect_timers = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

function IEex_GetGlobalEffectFlags()
	local tick = IEex_GetGameTick()
	local bitsOn = 0
	for bt = 0, 30, 1 do
		if ex_global_effect_timers[bt + 1] > tick then
			bitsOn = bit.bor(bitsOn, 2 ^ bt)
		end
	end
	return bitsOn
end

function IEex_SetGlobalEffectFlags(bitsOn, expirationTick)
	local tick = IEex_GetGameTick()
	for bt = 0, 30, 1 do
		if bit.band(bitsOn, 2 ^ bt) ~= 0 then
			IEex_SetGlobal("EX_GLOBEF" .. bt, expirationTick)
			ex_global_effect_timers[bt + 1] = expirationTick
		end
	end
	return false
end

function IEex_CheckGlobalEffect(bitCheck)
	local tick = IEex_GetGameTick()
	for bt = 0, 30, 1 do
		if bit.band(bitCheck, 2 ^ bt) ~= 0 and ex_global_effect_timers[bt + 1] > tick then
			return true
		end
	end
--[[
	local player1Data = IEex_GetActorShare(IEex_GetActorIDCharacter(0))
	if player1Data > 0 then
		local globalEffectFlags = IEex_ReadDword(player1Data + 0x73C)
		if globalEffectFlags ~= -1 and bit.band(globalEffectFlags, bitCheck) ~= 0 then
			return true
		end
	end
--]]
	return false
end

function IEex_CheckGlobalEffectOnActor(actorID, bitCheck)
	local globalEffectActive = false
	local isUnaffected = false
	if IEex_CheckGlobalEffect(bitCheck) then
		globalEffectActive = true
			local unaffectedFlags = 0
			IEex_IterateActorEffects(actorID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				local thespecial = IEex_ReadDword(eData + 0x48)
				if theopcode == 206 and theresource == "EXGLOBEF" then
					unaffectedFlags = bit.bor(unaffectedFlags, thespecial)
				end
			end)
			if bit.band(bitCheck, unaffectedFlags) == bitCheck then
				isUnaffected = true
			end
	end
--[[
	local player1Data = IEex_GetActorShare(IEex_GetActorIDCharacter(0))
	if player1Data > 0 then
		local globalEffectFlags = IEex_ReadDword(player1Data + 0x73C)
		if globalEffectFlags ~= -1 and bit.band(globalEffectFlags, bitCheck) > 0 then
			globalEffectActive = true
			local unaffectedFlags = 0
			IEex_IterateActorEffects(actorID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theresource = IEex_ReadLString(eData + 0x30, 8)
				local thespecial = IEex_ReadDword(eData + 0x48)
				if theopcode == 206 and theresource == "EXGLOBEF" then
					unaffectedFlags = bit.bor(unaffectedFlags, thespecial)
				end
			end)
			if bit.band(bitCheck, unaffectedFlags) == bitCheck then
				isUnaffected = true
			end
		end
	end
--]]
	return globalEffectActive, isUnaffected
end

function IEex_DuelHide(creatureData)
	local targetID = IEex_GetActorIDShare(creatureData)
	local duelActive, inDuel = IEex_CheckGlobalEffectOnActor(targetID, 0x1)
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	if duelActive and not IEex_InCutsceneMode() then
		if not inDuel then
			IEex_WriteWord(creatureData + 0x476, 0)
			if IEex_ReadByte(creatureData + 0x838, 0x0) == 0 then
				IEex_WriteDword(creatureData + 0x740, bit.bor(extraFlags, 0x2000))
				IEex_WriteByte(creatureData + 0x838, 1)
			end
		end
	else
		if bit.band(extraFlags, 0x2000) > 0 and extraFlags ~= -1 and extraFlags ~= -65536 and extraFlags ~= -50393088 then
			IEex_WriteDword(creatureData + 0x740, bit.band(extraFlags, 0xFFFFDFFF))
			IEex_WriteByte(creatureData + 0x838, 0)
		end
	end
end
--[[
function MEDUELCT(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	if actionID ~= 8 then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
--	local duelActive, inDuel = IEex_CheckGlobalEffectOnActor(sourceID, 0x1)
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	if bit.band(extraFlags, 0x2000) > 0 and extraFlags ~= -1 and extraFlags ~= -65536 and extraFlags ~= -50393088 then
		IEex_WriteDword(creatureData + 0x740, bit.band(extraFlags, 0xFFFFDFFF))
		IEex_WriteByte(creatureData + 0x838, 0)
	end
end

IEex_AddActionHookGlobal("MEDUELCT")
--]]
function MEMAGOCR(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	if actionID == 150 then
		local isMage = false
		for class, v in pairs(ex_courteous_magocracy_classes) do
			if IEex_GetActorStat(sourceID, class + 95) > 0 then
				isMage = true
			end
		end
		local targetID = IEex_ReadDword(creatureData + 0x4BE)
		local targetShare = IEex_GetActorShare(targetID)
		local tempFlags = IEex_ReadWord(targetShare + 0x9FA, 0x0)
		if IEex_IsSprite(targetID, false) and bit.band(IEex_ReadDword(targetShare + 0x75C), 0x400) > 0 and bit.band(tempFlags, 0x4) == 0 then
			IEex_WriteWord(targetShare + 0x9FA, bit.bor(tempFlags, 0x4))
			IEex_WriteWord(targetShare + 0x97E, IEex_ReadSignedWord(targetShare + 0x97E, 0x0) + ex_courteous_magocracy_charisma_bonus)
		end
	end
end

IEex_AddActionHookGlobal("MEMAGOCR")

function MESUMDLG(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	if actionID == 8 then
		local targetID = IEex_ReadDword(creatureData + 0x4BE)
		if targetID == sourceID then
			local summonerID = IEex_GetActorSummonerID(sourceID)
			if IEex_IsSprite(summonerID, false) then
				targetID = summonerID
				IEex_WriteDword(creatureData + 0x4BE, targetID)
			else
				actionID = 0
				IEex_WriteWord(creatureData + 0x476, actionID)
			end
		end
	end
end

IEex_AddActionHookGlobal("MESUMDLG")

ex_race_name_ref = {[10000] = 1096, [10001] = 5377, [10002] = 5378, [20000] = 1097, [20001] = 5379, [20002] = 5380, [30000] = 1098, [40000] = 1100, [40001] = 5381, [40002] = 5382, [50000] = 5374, [50001] = 5383, [50002] = 5384, [60000] = 1099, [60001] = 5385, [70000] = 23, }
ex_race_name_ref_less_specific = {[10000] = 1096, [10001] = 5377, [10002] = 5378, [20000] = 7194, [20001] = 5379, [20002] = 7194, [30000] = 1098, [40000] = 7182, [40001] = 7192, [40002] = 9295, [50000] = 7195, [50001] = 7195, [50002] = 7195, [60000] = 7196, [60001] = 7196, [70000] = 23, }
function MEDLGTOK(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	if actionID == 8 or actionID == 137 or actionID == 139 or actionID == 198 then
		local tokenRecipientID = IEex_ReadDword(creatureData + 0x4BE)
		if actionID == 139 then
			tokenRecipientID = sourceID
		end
		local recipientData = IEex_GetActorShare(tokenRecipientID)
		if recipientData <= 0 then return end
		local gender = IEex_ReadByte(recipientData + 0x34, 0x0)
		if gender == 1 then
			for k, v in pairs(ex_token_male) do
				IEex_SetToken(k, IEex_FetchString(v))
			end
		elseif gender == 2 then
			for k, v in pairs(ex_token_female) do
				IEex_SetToken(k, IEex_FetchString(v))
			end
		end
		local racePlusSub = IEex_ReadByte(recipientData + 0x26, 0x0) * 0x10000 + IEex_GetActorStat(targetID, 93)
		local raceStrref = 1
		if ex_race_name_ref_less_specific[racePlusSub] ~= nil then
			raceStrref = ex_race_name_ref_less_specific[racePlusSub]
		end
		IEex_SetToken("PRO_RACE", string.lower(IEex_FetchString(raceStrref)))
	end
end

IEex_AddActionHookGlobal("MEDLGTOK")

function MEPICKPO(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	if actionID == 25 then
		local targetID = IEex_ReadDword(creatureData + 0x4BE)
		local targetShare = IEex_GetActorShare(targetID)
		IEex_SetActionID(actionData, 191)
		IEex_CString_Set(creatureData + 0x538, "USPICKPO")
	end
end

--IEex_AddActionHookGlobal("MEPICKPO")

function MEPICKP2(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	if bit.band(extraFlags, 0x40000) > 0 and extraFlags ~= -1 then
		local summonerID = IEex_GetActorSummonerID(targetID)
		local summonerData = IEex_GetActorShare(summonerID)
		if summonerData > 0 then
			targetID = summonerID
			creatureData = summonerData
		end
	end
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local sourceData = IEex_GetActorShare(sourceID)
	if not IEex_IsSprite(sourceID, false) then return end
	local pickpocketSkill = IEex_GetActorStat(sourceID, 29) + IEex_ReadDword(effectData + 0x18)
	local detectionSkill = IEex_GetActorStat(targetID, 28)
	local loreSkill = IEex_GetActorStat(sourceID, 12)
	local possibleItemList = {}
	local atLeastOneItem = false
	for i = 0, 50, 1 do
		local slotData = IEex_ReadDword(creatureData + 0x4AD8 + i * 0x4)
		if slotData > 0 and ex_pick_pocket_slot_difficulty[i] < 32767 then
			local itemRES = IEex_ReadLString(slotData + 0xC, 8)
			local charges1 = IEex_ReadWord(slotData + 0x18, 0x0)
			local charges2 = IEex_ReadWord(slotData + 0x1A, 0x0)
			local charges3 = IEex_ReadWord(slotData + 0x1C, 0x0)
			local slotFlags = IEex_ReadDword(slotData + 0x20)
			if bit.band(slotFlags, 0x2) == 0 then
				local resWrapper = IEex_DemandRes(itemRES, "ITM")
				if resWrapper:isValid() then
					local itemData = resWrapper:getData()
					local nameRef = IEex_ReadDword(itemData + 0x8)
					local loreToIdentify = IEex_ReadSignedWord(itemData + 0x42, 0x0)
					local itemFlags = IEex_ReadDword(itemData + 0x18)
					if IEex_ReadDword(itemData + 0xC) > 0 and (bit.band(slotFlags, 0x1) > 0 or loreSkill >= loreToIdentify) then
						nameRef = IEex_ReadDword(itemData + 0xC)
					end
					if bit.band(itemFlags, 0x4) > 0 then
						atLeastOneItem = true
						possibleItemList[i] = {itemRES, charges1, charges2, charges3, slotFlags, nameRef, 0, 0}
					end
				end
				resWrapper:free()
			end
		end
	end
	local currentWeaponSet = IEex_ReadByte(creatureData + 0x4C68, 0x0)
	local highestSuccessChance = -32768
	local highestSuccessChanceSlot = -1
	local highestStealthChance = -32768
	local highestStealthChanceSlot = -1
	if atLeastOneItem then
		IEex_DisplayString("Possible items:")
	end
	local states = bit.bor(IEex_ReadDword(creatureData + 0x5BC), IEex_ReadDword(creatureData + 0x920))
	local successDifficultyAdjust = 0
	for state, stateV in pairs(ex_pick_pocket_state_difficulty_adjust) do
		if bit.band(states, state) ~= 0 and successDifficultyAdjust > stateV then
			successDifficultyAdjust = stateV
		end
	end
	local stealthDifficultyAdjust = 0
	for state, stateV in pairs(ex_pick_pocket_state_stealth_difficulty_adjust) do
		if bit.band(states, state) ~= 0 and stealthDifficultyAdjust > stateV then
			stealthDifficultyAdjust = stateV
		end
	end
	for k, v in pairs(possibleItemList) do
		local successChance = 100 - ((19 + ex_pick_pocket_slot_difficulty[k] - pickpocketSkill + successDifficultyAdjust) * 5)
		local stealthChance = 100 - ((9 + detectionSkill + ex_pick_pocket_slot_stealth_difficulty[k] - pickpocketSkill + stealthDifficultyAdjust) * 5)
		if k >= 43 and math.floor((k - 43) / 2) == currentWeaponSet then
			successChance = successChance - 50
			stealthChance = stealthChance - 100
		end
		if IEex_CompareActorAllegiances(sourceID, targetID) == -1 then
			successChance = successChance - 25
			stealthChance = stealthChance - 25
		end
		if IEex_ReadDword(creatureData + 0x4BE) == sourceID then
			successChance = successChance - 100
			stealthChance = stealthChance - 150
		end
		if successChance > 0 then
			if stealthChance >= highestStealthChance then
				highestStealthChance = stealthChance
				highestStealthChanceSlot = k
			end
			if stealthChance >= 100 and successChance >= highestSuccessChance then
				highestSuccessChance = successChance
				highestSuccessChanceSlot = k
			end
		end
		if successChance < 0 then
			successChance = 0
		elseif successChance > 100 then
			successChance = 100
		end
		if stealthChance < 0 then
			stealthChance = 0
		elseif stealthChance > 100 then
			stealthChance = 100
		end
		v[7] = successChance
		v[8] = stealthChance
	end
	local slotToSteal = -1
	if highestSuccessChanceSlot ~= -1 then
		slotToSteal = highestSuccessChanceSlot
	elseif highestStealthChanceSlot ~= -1 then
		slotToSteal = highestStealthChanceSlot
	end
	if slotToSteal ~= -1 then
		IEex_DisplayString("> " .. IEex_FetchString(possibleItemList[slotToSteal][6]) .. " - Success chance: " .. possibleItemList[slotToSteal][7] .. "%, Stealth chance: " .. possibleItemList[slotToSteal][8] .. "%")
	end
	for k, v in pairs(possibleItemList) do
		if k ~= slotToSteal then
			IEex_DisplayString(IEex_FetchString(v[6]) .. " - Success chance: " .. v[7] .. "%, Stealth chance: " .. v[8] .. "%")
		end
	end
	local pickpocketRoll = pickpocketSkill - successDifficultyAdjust + math.random(20)
	local detectionRoll = pickpocketSkill - stealthDifficultyAdjust + math.random(20)
	local isSuccess = false
	local isUndetected = false
	if slotToSteal >= 43 and math.floor((slotToSteal - 43) / 2) == currentWeaponSet then
		pickpocketRoll = pickpocketRoll - 10
		detectionRoll = detectionRoll - 10
	end
	if IEex_ReadDword(creatureData + 0x4BE) == sourceID then
		pickpocketRoll = pickpocketRoll - 10
		detectionRoll = detectionRoll - 10
	end
	if slotToSteal ~= -1 then
		if detectionRoll >= 10 + detectionSkill + ex_pick_pocket_slot_stealth_difficulty[slotToSteal] then
			isUndetected = true
		end
		if pickpocketRoll >= 20 + ex_pick_pocket_slot_difficulty[slotToSteal] then
			isSuccess = true
		end
	else
		if detectionRoll >= 10 + detectionSkill then
			isUndetected = true
		end
	end
	if isSuccess then
		if isUndetected then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55801,
["source_id"] = sourceID
})
		else
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55802,
["source_id"] = sourceID
})
		end
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 112,
["target"] = 2,
["timing"] = 1,
["resource"] = possibleItemList[slotToSteal][1],
["source_id"] = sourceID
})
		if possibleItemList[slotToSteal][1] ~= "MISC07" then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 122,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 32767,
["resource"] = possibleItemList[slotToSteal][1],
["source_id"] = sourceID
})
--			IEex_Eval("CreateItem(\"" .. possibleItemList[slotToSteal][1] .. "\", " .. possibleItemList[slotToSteal][2] .. ", " .. possibleItemList[slotToSteal][3] .. ", " .. 32767 .. ")", sourceID)
			for i = 18, 41, 1 do
				local slotData = IEex_ReadDword(sourceData + 0x4AD8 + i * 0x4)
				if slotData > 0 and ex_pick_pocket_slot_difficulty[i] < 32767 then
					local itemRES = IEex_ReadLString(slotData + 0xC, 8)
					local charges1 = IEex_ReadWord(slotData + 0x18, 0x0)
					if itemRES == possibleItemList[slotToSteal][1] and charges1 == 32767 then
						IEex_WriteWord(slotData + 0x18, possibleItemList[slotToSteal][2])
						IEex_WriteWord(slotData + 0x1A, possibleItemList[slotToSteal][3])
						IEex_WriteWord(slotData + 0x1C, possibleItemList[slotToSteal][4])
						IEex_WriteDword(slotData + 0x20, possibleItemList[slotToSteal][5])
					end
				end
			end
		else
			IEex_Eval("CreateItem(\"" .. possibleItemList[slotToSteal][1] .. "\", " .. possibleItemList[slotToSteal][2] .. ", 0, 0)", sourceID)
		end
	else
		if slotToSteal ~= -1 then
			if isUndetected then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55803,
["source_id"] = sourceID
})
			else
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55804,
["source_id"] = sourceID
})
			end
		else
			if highestStealthChance > 0 then
				if isUndetected then
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55805,
["source_id"] = sourceID
})
				else
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55806,
["source_id"] = sourceID
})
				end
			else
--[[
				if isUndetected then
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55807,
["source_id"] = sourceID
})
				else
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55808,
["source_id"] = sourceID
})
				end
--]]
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55809,
["source_id"] = sourceID
})
			end
		end
	end
	if not isUndetected and slotToSteal ~= -1 then
		if IEex_ReadByte(creatureData + 0x24, 0x0) >= 128 then
			IEex_SetActorLocal(targetID, "IEEX_PICK_POCKET_FAILED", 1)
		end
	end
end

function MEINTERA(actionData, creatureData)
--	if true then return false end
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
--[[
	if actionID == 23 or actionID == 112 then
		local containerID = 0
		local ids = IEex_GetIDArea(sourceID, 0x11)
		if ids[1] ~= 0 then
			IEex_Search(ids[1], creatureData, 0x8000, false)
		end
	end
--]]
	if actionID == 25 or actionID == 28 or actionID == 145 or actionID == 148 then
		local targetID = IEex_ReadDword(creatureData + 0x4BE)
		local targetShare = IEex_GetActorShare(targetID)

		if targetShare <= 0 then return end
		local targetX = IEex_ReadDword(targetShare + 0x6)
		local targetY = IEex_ReadDword(targetShare + 0xA)
		local objectType = IEex_ReadByte(targetShare + 0x4, 0x0)
		local sourceX = IEex_ReadDword(creatureData + 0x6)
		local sourceY = IEex_ReadDword(creatureData + 0xA)
		if objectType == 0x21 then
			local distOpenX = math.floor(IEex_ReadDword(targetShare + 0x5E0) / 16) - math.floor(sourceX / 16)
			local distOpenY = math.floor(IEex_ReadDword(targetShare + 0x5E4) / 12) - math.floor(sourceY / 12)
			local distClosedX = math.floor(IEex_ReadDword(targetShare + 0x5E8) / 16) - math.floor(sourceX / 16)
			local distClosedY = math.floor(IEex_ReadDword(targetShare + 0x5EC) / 12) - math.floor(sourceY / 12)
			if (distOpenX ^ 2 + distOpenY ^ 2) < (distClosedX ^ 2 + distClosedY ^ 2) then
				targetX = IEex_ReadDword(targetShare + 0x5E0)
				targetY = IEex_ReadDword(targetShare + 0x5E4)
			else
				targetX = IEex_ReadDword(targetShare + 0x5E8)
				targetY = IEex_ReadDword(targetShare + 0x5EC)
			end
		end
		
		if objectType == 0x11 or objectType == 0x21 then
			IEex_SetActionID(actionData, 23)
			IEex_WriteDword(creatureData + 0x540, targetX)
			IEex_WriteDword(creatureData + 0x544, targetY)
			IEex_WriteDword(creatureData + 0x556E, targetX)
			IEex_WriteDword(creatureData + 0x5572, targetY)
		else
			IEex_SetActionID(actionData, 22)
		end

		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 1,
["resource"] = "USINTERI",
["parent_resource"] = "USINTERI",
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 1,
["parameter1"] = actionID,
["parameter2"] = targetID,
["resource"] = "MEINTERI",
["target_x"] = targetX,
["target_y"] = targetY,
["parent_resource"] = "USINTERI",
["source_id"] = sourceID
})
	end
end

IEex_AddActionHookGlobal("MEINTERA")

function MEINTERI(effectData, creatureData, isSpecialCall)
	if not isSpecialCall then return end
--	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
--	if IEex_CheckForInfiniteLoop(targetID, IEex_GetGameTick(), "MEINTERA", 5) then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	local actionID = IEex_ReadWord(creatureData + 0x476, 0x0)
	local realActionID = IEex_ReadDword(effectData + 0x18)
	local actionTargetID = IEex_ReadDword(effectData + 0x1C)
	local targetShare = IEex_GetActorShare(actionTargetID)
	local sourceX = IEex_ReadDword(creatureData + 0x6)
	local sourceY = IEex_ReadDword(creatureData + 0xA)
	local targetX = IEex_ReadDword(effectData + 0x84)
	local targetY = IEex_ReadDword(effectData + 0x88)
	if realActionID == 25 and targetShare > 0 then
		targetX = IEex_ReadDword(targetShare + 0x6)
		targetY = IEex_ReadDword(targetShare + 0xA)
	end
	local destinationX = IEex_ReadDword(creatureData + 0x540)
	local destinationY = IEex_ReadDword(creatureData + 0x544)
	if ((actionID ~= 22 or (actionTargetID ~= IEex_ReadDword(creatureData + 0x4BE) and realActionID ~= 25)) and (actionID ~= 23 or targetX ~= destinationX or targetY ~= destinationY) and actionID ~= 83) or targetShare <= 0 then
		IEex_WriteDword(effectData + 0x110, 1)
		return
	end
	local distance = IEex_GetDistanceIsometric(sourceX, sourceY, targetX, targetY)
	local animationData = IEex_ReadDword(creatureData + 0x50F0)
	local reachX = IEex_ReadDword(animationData + 0x10)
	local reachY = IEex_ReadDword(animationData + 0x14)
	if reachX == 0 or reachY == 0 or IEex_ReadByte(animationData + 0x3E4, 0x0) == 0 then
		reachX = 65535
		reachY = 65535
	end
	local distX = math.floor(targetX / 16) - math.floor(sourceX / 16)
	local distY = math.floor(targetY / 12) - math.floor(sourceY / 12)
	
	local objectType = IEex_ReadByte(targetShare + 0x4, 0x0)
	local boxLeft = 0
	local boxTop = 0
	local boxRight = 0
	local boxBottom = 0
	if objectType == 0x11 then
		boxLeft = IEex_ReadDword(targetShare + 0x598)
		boxTop = IEex_ReadDword(targetShare + 0x59C)
		boxRight = IEex_ReadDword(targetShare + 0x5A0)
		boxBottom = IEex_ReadDword(targetShare + 0x5A4)
	elseif objectType == 0x21 then
		boxLeft = IEex_ReadDword(targetShare + 0x5B0)
		boxTop = IEex_ReadDword(targetShare + 0x5B4)
		boxRight = IEex_ReadDword(targetShare + 0x5B8)
		boxBottom = IEex_ReadDword(targetShare + 0x5BC)
	elseif objectType == 0x41 then
		boxLeft = IEex_ReadDword(targetShare + 0x59A)
		boxTop = IEex_ReadDword(targetShare + 0x59E)
		boxRight = IEex_ReadDword(targetShare + 0x5A2)
		boxBottom = IEex_ReadDword(targetShare + 0x5A6)
	end
	if realActionID == 25 then
		local castCounter = IEex_ReadSignedWord(creatureData + 0x54E8, 0x0)
		if distance <= ((reachY * 3) + 12) and castCounter == -1 then
			IEex_WriteWord(creatureData + 0x54E8, 85)
			IEex_ApplyEffectToActor(actionTargetID, {
["opcode"] = 146,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 1,
["parameter2"] = 1,
["resource"] = "USPICKPO",
["parent_resource"] = "USPICKPO",
["source_id"] = sourceID
})
--			IEex_PickPocket(sourceID, actionTargetID)
			IEex_WriteDword(effectData + 0x110, 1)
		end
	elseif realActionID == 28 then
		if objectType == 0x11 or objectType == 0x21 then
			if (distance <= reachY or ((sourceX + reachX >= boxLeft) and (sourceX - reachX <= boxRight) and (sourceY + reachY >= boxTop and sourceY - reachY <= boxBottom))) or distX ^ 2 + distY ^ 2 <= 16 then
				IEex_DisarmTrap(sourceID, actionTargetID)
				IEex_WriteDword(effectData + 0x110, 1)
			end
		elseif objectType == 0x41 then
			if (sourceX + reachX * 3 >= boxLeft) and (sourceX - reachX * 3 <= boxRight) and (sourceY + reachY * 3 >= boxTop and sourceY - reachY * 3 <= boxBottom) then
				IEex_DisarmTrap(sourceID, actionTargetID)
				IEex_WriteDword(effectData + 0x110, 1)
			end
		end
	elseif realActionID == 145 then
		if (distance <= reachY or ((sourceX + reachX >= boxLeft) and (sourceX - reachX <= boxRight) and (sourceY + reachY >= boxTop and sourceY - reachY <= boxBottom))) or distX ^ 2 + distY ^ 2 <= 16 then
			IEex_PickLock(sourceID, actionTargetID)
			IEex_WriteDword(effectData + 0x110, 1)
		end
	elseif realActionID == 148 then
		if distance <= reachY or ((sourceX + reachX >= boxLeft) and (sourceX - reachX <= boxRight) and (sourceY + reachY >= boxTop and sourceY - reachY <= boxBottom)) or distX ^ 2 + distY ^ 2 <= 16 then
			IEex_BashLock(sourceID, actionTargetID)
			IEex_WriteDword(effectData + 0x110, 1)
		end
	end
end
--[[
function IEex_PickPocket(sourceID, targetID)
	local creatureData = IEex_GetActorShare(targetID)
	local sourceData = IEex_GetActorShare(sourceID)
	if not IEex_IsSprite(sourceID, false) or creatureData <= 0 then return end
	local pickpocketSkill = IEex_GetActorStat(sourceID, 29)
	local detectionSkill = IEex_GetActorStat(targetID, 28)
	local possibleItemList = {}
	for i = 0, 50, 1 do
		local slotData = IEex_ReadDword(creatureData + 0x4AD8 + i * 0x4)
		if slotData > 0 and ex_pick_pocket_slot_difficulty[i] < 32767 then
			local itemRES = IEex_ReadLString(slotData + 0xC, 8)
			local charges1 = IEex_ReadWord(slotData + 0x18, 0x0)
			local charges2 = IEex_ReadWord(slotData + 0x1A, 0x0)
			local charges3 = IEex_ReadWord(slotData + 0x1C, 0x0)
			local slotFlags = IEex_ReadDword(slotData + 0x20)
			if bit.band(slotFlags, 0x2) == 0 then
				local resWrapper = IEex_DemandRes(itemRES, "ITM")
				if resWrapper:isValid() then
					local itemData = resWrapper:getData()
					if bit.band(IEex_ReadDword(itemData + 0x18), 0x4) > 0 then
						possibleItemList[i] = {itemRES, charges1, charges2, charges3, slotFlags}
					end
				end
				resWrapper:free()
			end
		end
	end
	local currentWeaponSet = IEex_ReadByte(creatureData + 0x4C68, 0x0)
	local highestSuccessChance = -32768
	local highestSuccessChanceSlot = -1
	local highestStealthChance = -32768
	local highestStealthChanceSlot = -1
	for k, v in pairs(possibleItemList) do
		local successChance = 100 - ((19 + ex_pick_pocket_slot_difficulty[k] - pickpocketSkill) * 5)
		local stealthChance = 100 - ((9 + detectionSkill + ex_pick_pocket_slot_stealth_difficulty[k] - pickpocketSkill) * 5)
		if k >= 43 and math.floor((k - 43) / 2) == currentWeaponSet then
			successChance = successChance - 50
			stealthChance = stealthChance - 50
		end
		if IEex_ReadDword(creatureData + 0x4BE) == sourceID then
			successChance = successChance - 50
			stealthChance = stealthChance - 50
		end
		if successChance > 0 then
			if stealthChance >= highestStealthChance then
				highestStealthChance = stealthChance
				highestStealthChanceSlot = k
			end
			if stealthChance >= 100 and successChance >= highestSuccessChance then
				highestSuccessChance = successChance
				highestSuccessChanceSlot = k
			end
		end
	end
	local slotToSteal = -1
	if highestSuccessChanceSlot ~= -1 then
		slotToSteal = highestSuccessChanceSlot
	elseif highestStealthChanceSlot ~= -1 then
		slotToSteal = highestStealthChanceSlot
	end
	local pickpocketRoll = pickpocketSkill + math.random(20)
	local detectionRoll = pickpocketSkill + math.random(20)
	local isSuccess = false
	local isUndetected = false
	if slotToSteal >= 43 and math.floor((slotToSteal - 43) / 2) == currentWeaponSet then
		pickpocketRoll = pickpocketRoll - 10
		detectionRoll = detectionRoll - 10
	end
	if IEex_ReadDword(creatureData + 0x4BE) == sourceID then
		pickpocketRoll = pickpocketRoll - 10
		detectionRoll = detectionRoll - 10
	end
	if slotToSteal ~= -1 then
		if detectionRoll >= 10 + detectionSkill + ex_pick_pocket_slot_stealth_difficulty[slotToSteal] then
			isUndetected = true
		end
		if pickpocketRoll >= 20 + ex_pick_pocket_slot_difficulty[slotToSteal] then
			isSuccess = true
		end
	else
		if detectionRoll >= 10 + detectionSkill then
			isUndetected = true
		end
	end
	if isSuccess then
		if isUndetected then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55801,
["source_id"] = sourceID
})
		else
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55802,
["source_id"] = sourceID
})
		end
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 112,
["target"] = 2,
["timing"] = 1,
["resource"] = possibleItemList[slotToSteal][1],
["source_id"] = sourceID
})
		if possibleItemList[slotToSteal][1] ~= "MISC07" then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 122,
["target"] = 2,
["timing"] = 1,
["parameter1"] = 32767,
["resource"] = possibleItemList[slotToSteal][1],
["source_id"] = sourceID
})
--			IEex_Eval("CreateItem(\"" .. possibleItemList[slotToSteal][1] .. "\", " .. possibleItemList[slotToSteal][2] .. ", " .. possibleItemList[slotToSteal][3] .. ", " .. 32767 .. ")", sourceID)
			for i = 18, 41, 1 do
				local slotData = IEex_ReadDword(sourceData + 0x4AD8 + i * 0x4)
				if slotData > 0 and ex_pick_pocket_slot_difficulty[i] < 32767 then
					local itemRES = IEex_ReadLString(slotData + 0xC, 8)
					local charges1 = IEex_ReadWord(slotData + 0x18, 0x0)
					if itemRES == possibleItemList[slotToSteal][1] and charges1 == 32767 then
						IEex_WriteWord(slotData + 0x18, possibleItemList[slotToSteal][2])
						IEex_WriteWord(slotData + 0x1A, possibleItemList[slotToSteal][3])
						IEex_WriteWord(slotData + 0x1C, possibleItemList[slotToSteal][4])
						IEex_WriteDword(slotData + 0x20, possibleItemList[slotToSteal][5])
					end
				end
			end
		else
			IEex_Eval("CreateItem(\"" .. possibleItemList[slotToSteal][1] .. "\", " .. possibleItemList[slotToSteal][2] .. ", 0, 0)", sourceID)
		end
	else
		if slotToSteal ~= -1 then
			if isUndetected then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55803,
["source_id"] = sourceID
})
			else
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55804,
["source_id"] = sourceID
})
			end
		else
			if highestSuccessChance > 0 then
				if isUndetected then
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55805,
["source_id"] = sourceID
})
				else
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55806,
["source_id"] = sourceID
})
				end
			else
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55809,
["source_id"] = sourceID
})
			end
		end
	end
	if not isUndetected and highestSuccessChance > 0 then
		if IEex_ReadByte(creatureData + 0x24, 0x0) >= 128 then
			IEex_SetActorLocal(targetID, "IEEX_PICK_POCKET_FAILED", 1)
		end
	end
end
--]]
function IEex_DisarmTrap(sourceID, targetID)
	local creatureData = IEex_GetActorShare(targetID)
	local sourceData = IEex_GetActorShare(sourceID)
	if not IEex_IsSprite(sourceID, false) or creatureData <= 0 then return end
	local disableDeviceSkill = IEex_GetActorStat(sourceID, 233)
	local objectType = IEex_ReadByte(creatureData + 0x4, 0x0)
	if objectType == 0x11 then 
		if IEex_ReadByte(creatureData + 0x896, 0x0) > 0 then
			local trapDifficulty = IEex_ReadWord(creatureData + 0x894, 0x0)
			if trapDifficulty == 100 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 1608,
["source_id"] = sourceID
})
				return
			end
			if disableDeviceSkill + math.random(4) >= math.floor(trapDifficulty / 5) then
				local flags = IEex_ReadDword(creatureData + 0x88E)
				IEex_WriteDword(creatureData + 0x88E, bit.bor(flags, 0x2000000))
				IEex_WriteByte(creatureData + 0x896, 0)
				IEex_WriteByte(creatureData + 0x898, 0)
				IEex_WriteWord(creatureData + 0x8D0, 0)
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 16520,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 9,
["resource"] = "ACT_09",
["source_id"] = sourceID
})
				local successXP = trapDifficulty * ex_disarm_trap_xp_multiplier
				if successXP > 0 then
--					IEex_Eval('AddexperienceParty(' .. successXP .. ')', sourceID)
					IEex_AddPartyXP(successXP, true, false)
				end
			else
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 1608,
["source_id"] = sourceID
})
				return
			end
		end
	elseif objectType == 0x21 then
		if IEex_ReadByte(creatureData + 0x64C, 0x0) > 0 then
			local trapDifficulty = IEex_ReadWord(creatureData + 0x64A, 0x0)
			if trapDifficulty == 100 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 1608,
["source_id"] = sourceID
})
				return
			end
			if disableDeviceSkill + math.random(4) >= math.floor(trapDifficulty / 5) then
				local flags = IEex_ReadDword(creatureData + 0x5C4)
				IEex_WriteDword(creatureData + 0x5C4, bit.bor(flags, 0x2000000))
				IEex_WriteByte(creatureData + 0x64C, 0)
				IEex_WriteByte(creatureData + 0x64E, 0)
				IEex_WriteWord(creatureData + 0x664, 0)
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 16520,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 9,
["resource"] = "ACT_09",
["source_id"] = sourceID
})
				local successXP = trapDifficulty * ex_disarm_trap_xp_multiplier
				if successXP > 0 then
--					IEex_Eval('AddexperienceParty(' .. successXP .. ')', sourceID)
					IEex_AddPartyXP(successXP, true, false)
				end
			else
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 1608,
["source_id"] = sourceID
})
				return
			end
		end
	elseif objectType == 0x41 then
		IEex_WriteWord(sourceData + 0x476, 22)
		IEex_WriteDword(sourceData + 0x4BE, sourceID)
		IEex_WriteDword(sourceData + 0x556E, IEex_ReadDword(sourceData + 0x6))
		IEex_WriteDword(sourceData + 0x5572, IEex_ReadDword(sourceData + 0xA))
		if IEex_ReadByte(creatureData + 0x612, 0x0) > 0 then
			local trapDifficulty = IEex_ReadWord(creatureData + 0x610, 0x0)
			if trapDifficulty == 100 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 1608,
["source_id"] = sourceID
})
				return
			end
			if disableDeviceSkill + math.random(4) >= math.floor(trapDifficulty / 5) then
				local flags = IEex_ReadDword(creatureData + 0x5D6)
				IEex_WriteDword(creatureData + 0x5D6, bit.bor(flags, 0x2000000))
				IEex_WriteByte(creatureData + 0x612, 0)
				IEex_WriteByte(creatureData + 0x614, 0)
				IEex_WriteWord(creatureData + 0x626, 0)
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 16520,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 9,
["resource"] = "ACT_09",
["source_id"] = sourceID
})
				local successXP = trapDifficulty * ex_disarm_trap_xp_multiplier
				if successXP > 0 then
--					IEex_Eval('AddexperienceParty(' .. successXP .. ')', sourceID)
					IEex_AddPartyXP(successXP, true, false)
				end
			else
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 1608,
["source_id"] = sourceID
})
				return
			end
		end
	end
end

function IEex_PickLock(sourceID, targetID)
	local creatureData = IEex_GetActorShare(targetID)
	local sourceData = IEex_GetActorShare(sourceID)
	if not IEex_IsSprite(sourceID, false) or creatureData <= 0 then return end
	local lockpickingSkill = IEex_GetActorStat(sourceID, 26)
	local objectType = IEex_ReadByte(creatureData + 0x4, 0x0)
	if objectType == 0x11 then
		local objectFlags = IEex_ReadDword(creatureData + 0x88E)
		if bit.band(objectFlags, 0x1) > 0 then
			local lockDifficulty = IEex_ReadWord(creatureData + 0x88C, 0x0)
			if lockDifficulty == 100 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 23169,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 9,
["resource"] = "AMB_D21",
["source_id"] = sourceID
})
				return
			end
			if bit.band(objectFlags, 0x200000) > 0 then
				if bit.band(objectFlags, 0x100000) > 0 then
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55814,
["source_id"] = sourceID
})
				else
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55810,
["source_id"] = sourceID
})
				end
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 9,
["resource"] = "AMB_D21",
["source_id"] = sourceID
})
				return
			end
			if (lockpickingSkill + math.random(4)) * 5 >= lockDifficulty then
				objectFlags = bit.band(objectFlags, 0xFFFFFFFE)
				objectFlags = bit.bor(objectFlags, 0x1000000)
				IEex_WriteDword(creatureData + 0x88E, objectFlags)
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 16517,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 9,
["resource"] = "AMB_D21D",
["source_id"] = sourceID
})
				local successXP = lockDifficulty * ex_lockpicking_xp_multiplier
				if successXP > 0 then
--					IEex_Eval('AddexperienceParty(' .. successXP .. ')', sourceID)
					IEex_AddPartyXP(successXP, true, false)
				end
			else
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 16518,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 9,
["resource"] = "AMB_D21",
["source_id"] = sourceID
})
				return
			end
		end
	elseif objectType == 0x21 then
		local objectFlags = IEex_ReadDword(creatureData + 0x5C4)
		if bit.band(objectFlags, 0x2) > 0 then
			local lockDifficulty = IEex_ReadWord(creatureData + 0x660, 0x0)
			if lockDifficulty == 100 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 23169,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 9,
["resource"] = "AMB_D21",
["source_id"] = sourceID
})
				return
			end
			if bit.band(objectFlags, 0x200000) > 0 then
				if bit.band(objectFlags, 0x100000) > 0 then
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55813,
["source_id"] = sourceID
})
				else
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55810,
["source_id"] = sourceID
})
				end
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 9,
["resource"] = "AMB_D21",
["source_id"] = sourceID
})
				return
			end
			if (lockpickingSkill + math.random(4)) * 5 >= lockDifficulty then
				objectFlags = bit.band(objectFlags, 0xFFFFFFFD)
				objectFlags = bit.bor(objectFlags, 0x1000000)
				IEex_WriteDword(creatureData + 0x5C4, objectFlags)
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 16517,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 9,
["resource"] = "AMB_D21D",
["source_id"] = sourceID
})
				local successXP = lockDifficulty * ex_lockpicking_xp_multiplier
				if successXP > 0 then
--					IEex_Eval('AddexperienceParty(' .. successXP .. ')', sourceID)
					IEex_AddPartyXP(successXP, true, false)
				end
			else
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 16518,
["source_id"] = sourceID
})
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 174,
["target"] = 2,
["timing"] = 9,
["resource"] = "AMB_D21",
["source_id"] = sourceID
})
				return
			end
		end
	end
end

function IEex_BashLock(sourceID, targetID)
	local creatureData = IEex_GetActorShare(targetID)
	local sourceData = IEex_GetActorShare(sourceID)
	if not IEex_IsSprite(sourceID, false) or creatureData <= 0 then return end
	local strengthBonus = (IEex_GetActorStat(sourceID, 36) - 10) / 2
	local objectType = IEex_ReadByte(creatureData + 0x4, 0x0)
	if objectType == 0x11 then
		local objectFlags = IEex_ReadDword(creatureData + 0x88E)
		if bit.band(objectFlags, 0x1) > 0 then
			local lockDifficulty = IEex_ReadWord(creatureData + 0x88C, 0x0)
			if lockDifficulty == 100 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 9914,
["source_id"] = sourceID
})
				return
			end
			if bit.band(objectFlags, 0x100000) > 0 then
				if bit.band(objectFlags, 0x200000) > 0 then
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55814,
["source_id"] = sourceID
})
				else
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55812,
["source_id"] = sourceID
})
				end
				return
			end
			local roll = math.random(4)
			if (strengthBonus + roll) * 5 >= lockDifficulty / 5 or roll == 4 and lockDifficulty <= 5 then
				objectFlags = bit.band(objectFlags, 0xFFFFFFFE)
				objectFlags = bit.bor(objectFlags, 0x1000000)
				IEex_WriteDword(creatureData + 0x88E, objectFlags)
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 9916,
["source_id"] = sourceID
})
			else
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 9914,
["source_id"] = sourceID
})
				return
			end
		end
	elseif objectType == 0x21 then
		local objectFlags = IEex_ReadDword(creatureData + 0x5C4)
		if bit.band(objectFlags, 0x2) > 0 then
			local lockDifficulty = IEex_ReadWord(creatureData + 0x660, 0x0)
			if lockDifficulty == 100 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 9914,
["source_id"] = sourceID
})
				return
			end
			if bit.band(objectFlags, 0x100000) > 0 then
				if bit.band(objectFlags, 0x200000) > 0 then
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55813,
["source_id"] = sourceID
})
				else
					IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55811,
["source_id"] = sourceID
})
				end
				return
			end
			if (strengthBonus + math.random(4)) * 5 >= lockDifficulty then
				objectFlags = bit.band(objectFlags, 0xFFFFFFFD)
				objectFlags = bit.bor(objectFlags, 0x1000000)
				IEex_WriteDword(creatureData + 0x5C4, objectFlags)
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 9916,
["source_id"] = sourceID
})
			else
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = 9914,
["source_id"] = sourceID
})
				return
			end
		end
	end
end

function MEKNOCKF(effectData, creatureData)
--	local creatureData = IEex_GetActorShare(targetID)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_Helper_GetBridge("IEex_RecordSpell", sourceID, "targetID")
	if targetID == nil then return end
	creatureData = IEex_GetActorShare(targetID)
	local objectType = IEex_ReadByte(creatureData + 0x4, 0x0)
	if objectType == 0x11 then
		local objectFlags = IEex_ReadDword(creatureData + 0x88E)
		if bit.band(objectFlags, 0x1) > 0 then
			local lockDifficulty = IEex_ReadWord(creatureData + 0x88C, 0x0)
			if lockDifficulty == 100 then
				return
			end
			objectFlags = bit.bor(objectFlags, 0x1000000)
			IEex_WriteDword(creatureData + 0x88E, objectFlags)
		end
	elseif objectType == 0x21 then
		local objectFlags = IEex_ReadDword(creatureData + 0x5C4)
		if bit.band(objectFlags, 0x2) > 0 then
			local lockDifficulty = IEex_ReadWord(creatureData + 0x660, 0x0)
			if lockDifficulty == 100 then
				return
			end
			objectFlags = bit.bor(objectFlags, 0x1000000)
			IEex_WriteDword(creatureData + 0x5C4, objectFlags)
		end
	end
end

function MECHAOCA(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local targetID = IEex_GetActorIDShare(creatureData)
	local savingthrow = IEex_ReadDword(effectData + 0x3C)
	local minLevel = IEex_ReadDword(effectData + 0x18)
	local maxLevel = IEex_ReadDword(effectData + 0x1C)
	if minLevel <= 0 or minLevel > 9 then
		minLevel = 1
	end
	if maxLevel <= 0 or maxLevel > 9 then
		maxLevel = 9
	end
	if minLevel > maxLevel then return end
	local randomSpellTable = ex_chaos_cast_enemy
	local cea = IEex_CompareActorAllegiances(sourceID, targetID)
	if sourceID == targetID then
		randomSpellTable = ex_chaos_cast_self
	elseif cea == 1 then
		randomSpellTable = ex_chaos_cast_ally
	end
	local randomSpellLevelTable = randomSpellTable[math.random(minLevel, maxLevel)]
	local randomSpell = randomSpellLevelTable[math.random(#randomSpellLevelTable)]
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local resWrapper = IEex_DemandRes(randomSpell, "SPL")
	if resWrapper:isValid() then
		local spellData = resWrapper:getData()
		IEex_SetToken("EXCCSPELL", IEex_FetchString(IEex_ReadDword(spellData + 0x8)))
	else
		resWrapper:free()
		return
	end
	resWrapper:free()
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55716,
["source_id"] = sourceID
})
	IEex_WriteWord(creatureData + 0x54E8, -1)
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 146,
["target"] = 2,
["timing"] = 9,
["parameter1"] = bit.band(casterlvl, 0xFF),
["parameter2"] = 0,
--["savingthrow"] = 0x10000,
["resource"] = randomSpell,
["source_x"] = IEex_ReadDword(effectData + 0x7C),
["source_y"] = IEex_ReadDword(effectData + 0x80),
["target_x"] = IEex_ReadDword(effectData + 0x84),
["target_y"] = IEex_ReadDword(effectData + 0x88),
["parent_resource"] = randomSpell,
["internal_flags"] = bit.bor(IEex_ReadDword(effectData + 0xCC), IEex_ReadDword(effectData + 0xD4)),
["casterlvl"] = casterlvl,
["source_target"] = targetID,
["source_id"] = sourceID
})
IEex_WriteWord(creatureData + 0x54E8, 0)
end

ex_ailment_contingency_conditions = {["SPPR103"] = 1, ["SPPR108"] = 10, ["SPPR212"] = 11, ["SPPR214"] = 1, ["SPPR307"] = 12, ["SPPR308"] = 13, ["SPPR314"] = 14, ["SPPR316"] = 15, ["SPPR401"] = 1, ["SPPR404"] = 16, ["SPPR426"] = 17, ["SPPR502"] = 1, ["SPPR607"] = 9, ["SPPR725"] = 59, ["USPR753"] = 9, ["USPR754"] = 1, ["SPWI203"] = 18, ["SPWI210"] = 10, ["SPWI219"] = 19, ["SPWI410"] = 12, ["SPWI614"] = 21, }
function MEAILCON(originatingEffectData, actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	local parameter1 = IEex_ReadDword(originatingEffectData + 0x18)
	local parameter3 = IEex_ReadDword(originatingEffectData + 0x5C)
	local special = IEex_ReadDword(originatingEffectData + 0x44) * IEex_GetActorStat(sourceID, 54)
	if parameter3 == 1 then return end
	if actionID == 31 or actionID == 113 or actionID == 181 or actionID == 191 then
		local targetID = IEex_ReadDword(creatureData + 0x4BE)
		if not IEex_IsSprite(targetID, false) then return end
		local spellRES = IEex_GetActorSpellRES(sourceID)
		local resWrapper = IEex_DemandRes(spellRES, "SPL")
		if resWrapper:isValid() then
			local spellData = resWrapper:getData()
			IEex_SetToken("EXACVAL1", IEex_FetchString(IEex_ReadDword(spellData + 0x8)))
		end
		resWrapper:free()
		local classSpellLevel = IEex_GetClassSpellLevel(sourceID, IEex_ReadByte(originatingEffectData + 0xC5, 0x0), spellRES)
		if ex_ailment_contingency_conditions[spellRES] == nil or classSpellLevel > parameter1 or classSpellLevel == 0 then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55500,
["source_id"] = sourceID
})
			return
		end
		IEex_WriteDword(originatingEffectData + 0x5C, 1)
		local casterlvl = IEex_ReadDword(originatingEffectData + 0xC4)
		local parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
		local internalContingencyRES = parent_resource .. "S"
		if #internalContingencyRES > 8 then
			internalContingencyRES = "MEAILCON"
		end

		local playerIndex = -1
		for i = 0, 5, 1 do
			if sourceID == IEex_GetActorIDCharacter(i) then
				playerIndex = i
			end
		end
		if IEex_GetGlobal("EX_Recording_Buffs") == 1 then
			if actionID == 31 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 0,
["resource"] = "MEBUFFRC",
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
			elseif actionID == 95 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 1,
["resource"] = "MEBUFFRC",
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
			end
		end
		IEex_SetActionID(actionData, 0)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = internalContingencyRES,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 148,
["target"] = 2,
["timing"] = 9,
["resource"] = "USAILCOE",
["parent_resource"] = internalContingencyRES,
["source_x"] = IEex_ReadDword(creatureData + 0x6),
["source_y"] = IEex_ReadDword(creatureData + 0xA),
["target_x"] = IEex_ReadDword(IEex_GetActorShare(targetID) + 0x6),
["target_y"] = IEex_ReadDword(IEex_GetActorShare(targetID) + 0xA),
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 9,
["parameter2"] = 69,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = -1,
["parameter2"] = classSpellLevel,
["special"] = classSpellLevel,
["savingthrow"] = 0x2000000,
["resource"] = "EXMODMEM",
["vvcresource"] = spellRES,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 0,
["duration"] = special,
["parameter4"] = playerIndex,
["savingthrow"] = 0x2000000,
["vvcresource"] = spellRES,
["resource2"] = parent_resource,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = special,
["parameter2"] = 224,
["resource"] = "USAILCON",
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55598,
["source_id"] = sourceID
})
	elseif actionID == 95 or actionID == 114 or actionID == 192 then
		local spellRES = IEex_GetActorSpellRES(sourceID)
		local resWrapper = IEex_DemandRes(spellRES, "SPL")
		if resWrapper:isValid() then
			local spellData = resWrapper:getData()
			IEex_SetToken("EXACVAL1", IEex_FetchString(IEex_ReadDword(spellData + 0x8)))
		end
		resWrapper:free()
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55500,
["source_id"] = sourceID
})
	end
end

IEex_AddActionHookOpcode("MEAILCON")

function MEAILCO2(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = 0
	local spellRES = ""
	local internalContingencyRES = ""
	local casterlvl = 1
	IEex_IterateActorEffects(targetID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		if theopcode == 0 and bit.band(thesavingthrow, 0x2000000) > 0 then
			spellRES = IEex_ReadLString(eData + 0x70, 8)
			internalContingencyRES = IEex_ReadLString(eData + 0x94, 8)
			casterlvl = IEex_ReadDword(eData + 0xC8)
			sourceID = IEex_ReadDword(eData + 0x110)
			if sourceID <= 0 then
				sourceID = IEex_GetActorIDCharacter(IEex_ReadDword(eData + 0x64))
			end
			if sourceID <= 0 then
				sourceID = targetID
			end
		end
	end)
	local condition = ex_ailment_contingency_conditions[spellRES]
	if condition == nil then return end
	local conditionMet = false
	if condition == 1 and IEex_ReadSignedWord(creatureData + 0x5C0, 0x0) / IEex_GetActorStat(targetID, 1) < .4 then
		conditionMet = true
	elseif condition == 9 and (IEex_ReadSignedWord(creatureData + 0x5C0, 0x0) / IEex_GetActorStat(targetID, 1) < .4 or IEex_GetActorState(targetID, 0x1C4000)) then
		conditionMet = true
	elseif condition == 10 and IEex_GetActorState(targetID, 0x4) then
		conditionMet = true
	elseif condition == 11 and (IEex_GetActorState(targetID, 0x4000) or IEex_GetActorStat(targetID, 31) >= 50) then
		conditionMet = true
	elseif condition == 12 and IEex_GetActorState(targetID, 0x80102023) then
		conditionMet = true
	elseif condition == 13 and IEex_GetActorState(targetID, 0x28) then
		conditionMet = true
	elseif condition == 14 and IEex_GetActorState(targetID, 0x80000) then
		conditionMet = true
	elseif condition == 15 and (IEex_GetActorState(targetID, 0x80100007) or IEex_GetActorSpellState(targetID, 0) or IEex_GetActorStat(targetID, 31) >= 50) then
		conditionMet = true
	elseif condition == 16 and (IEex_GetActorState(targetID, 0x4000) or IEex_GetActorStat(targetID, 31) >= 50) then
		conditionMet = true
	elseif condition == 17 and IEex_GetActorSpellState(targetID, 57) then
		conditionMet = true
	elseif condition == 18 and IEex_GetActorState(targetID, 0x40000) then
		conditionMet = true
	elseif condition == 19 and IEex_GetActorState(targetID, 0x1000) then
		conditionMet = true
	elseif condition == 20 and IEex_GetActorState(targetID, 0x10000) then
		conditionMet = true
	elseif condition == 21 and IEex_GetActorState(targetID, 0x80) then
		conditionMet = true
	elseif condition == 59 and (IEex_ReadSignedWord(creatureData + 0x5C0, 0x0) / IEex_GetActorStat(targetID, 1) < .4 or IEex_GetActorState(targetID, 0x801D70AF) or IEex_GetActorSpellState(targetID, 57)) then
		conditionMet = true
	end
	if not conditionMet then return end
	local resWrapper = IEex_DemandRes(spellRES, "SPL")
	local projectile = 0
	if resWrapper:isValid() then
		local spellData = resWrapper:getData()
		projectile = IEex_ReadWord(spellData + 0xA8, 0x0) - 1
	end
	resWrapper:free()
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55599,
["source_id"] = targetID
})
	if projectile == 0 then
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 9,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
	else
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 430,
["target"] = 2,
["timing"] = 9,
["parameter2"] = projectile,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
	end
	IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = internalContingencyRES,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
	IEex_WriteDword(effectData + 0x110, 1)
end

ex_target_ability_suffix = {[0] = "D", [1] = "D", [2] = "D", [3] = "D", [4] = "P", [5] = "S", [6] = "D", [7] = "S", [99] = "T"}
function MESPLSEQ(originatingEffectData, actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	local numSpells = IEex_ReadWord(originatingEffectData + 0x18, 0x0)
	local maxSpellLevel = IEex_ReadWord(originatingEffectData + 0x1A, 0x0)
	local savingthrow = IEex_ReadDword(originatingEffectData + 0x3C)
	if maxSpellLevel == 0 then
		maxSpellLevel = 9
	end
	local special = IEex_ReadDword(originatingEffectData + 0x44)
	if numSpells <= 0 then return end
	if actionID == 31 or actionID == 95 or actionID == 113 or actionID == 114 or actionID == 181 or actionID == 191 or actionID == 192 then
		
		local spellRES = IEex_GetActorSpellRES(sourceID)
		local resWrapper = IEex_DemandRes(spellRES, "SPL")
		local spellTarget = 1
		local spellType = 1
		local spellRange = 1
		local spellSchool = 0
		local baseSpellLevel = 0
		if resWrapper:isValid() then
			local spellData = resWrapper:getData()
			spellType = IEex_ReadWord(spellData + 0x1C, 0x0)
			spellSchool = IEex_ReadByte(spellData + 0x25, 0x0)
			spellTarget = IEex_ReadByte(spellData + 0x8E, 0x0)
			spellRange = IEex_ReadWord(spellData + 0x90, 0x0)
			IEex_SetToken("EXACVAL1", IEex_FetchString(IEex_ReadDword(spellData + 0x8)))
		end
		resWrapper:free()
		if spellType < 1 or spellType > 2 then return end
		if ex_trueschool[spellRES] ~= nil then
			spellSchool = ex_trueschool[spellRES]
		end
		local casterClass = IEex_ReadSignedByte(creatureData + 0x530, 0x0)
		local classSpellLevel = IEex_ReadSignedByte(creatureData + 0x534, 0x0)
		if classSpellLevel <= 0 then
			classSpellLevel = IEex_GetClassSpellLevel(sourceID, IEex_ReadByte(originatingEffectData + 0xC5, 0x0), spellRES)
		end
		if classSpellLevel > maxSpellLevel then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55596,
["source_id"] = sourceID
})
			return
		end
		local casterlvl = IEex_ReadDword(originatingEffectData + 0xC4)
		local parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
		if bit.band(savingthrow, 0x100000) > 0 then
			if spellSchool < 1 or spellSchool > 8 then return end
			local schoolAlreadyStored = false
			IEex_IterateActorEffects(sourceID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local thesavingthrow = IEex_ReadDword(eData + 0x40)
				local theparameter3 = IEex_ReadDword(eData + 0x60)
				local theresource2 = IEex_ReadLString(eData + 0x78, 8)
				if theopcode == 0 and bit.band(thesavingthrow, 0x4000000) > 0 and theresource2 == parent_resource and theparameter3 == spellSchool then
					schoolAlreadyStored = true
				end
			end)
			if schoolAlreadyStored then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55590,
["source_id"] = sourceID
})
				return
			end
		end
		numSpells = numSpells - 1
		IEex_WriteWord(originatingEffectData + 0x18, numSpells)
		local internalContingencySuffix = ex_target_ability_suffix[spellTarget]
		if spellTarget == 1 and spellRange <= 1 then
			internalContingencySuffix = ex_target_ability_suffix[99]
		end
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			local theresource2 = IEex_ReadLString(eData + 0x78, 8)
			if theopcode == 0 and bit.band(thesavingthrow, 0x4000000) > 0 and theresource2 == parent_resource then
				local theinternalContingencySuffix = IEex_ReadLString(eData + 0x9B, 1)
				if theinternalContingencySuffix == "T" then
					internalContingencySuffix = "T"
				elseif theinternalContingencySuffix == "D" and (internalContingencySuffix == "S" or internalContingencySuffix == "P") then
					internalContingencySuffix = "D"
				elseif theinternalContingencySuffix == "P" and internalContingencySuffix == "S" then
					internalContingencySuffix = "P"
				end
			end
		end)
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			local theresource2 = IEex_ReadLString(eData + 0x78, 8)
			if theopcode == 0 and bit.band(thesavingthrow, 0x4000000) > 0 and theresource2 == parent_resource then
				IEex_WriteLString(eData + 0x9B, internalContingencySuffix, 1)
			end
		end)
		local internalContingencyRES = parent_resource .. internalContingencySuffix
		if #internalContingencyRES > 8 then
			internalContingencyRES = "MESPLSEQ"
		end
		IEex_SetActionID(actionData, 0)
		local newTiming = 0
		if special == 0 then
			newTiming = 9
		end
		if IEex_GetGlobal("EX_Recording_Buffs") == 1 then
			if actionID == 31 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 0,
["resource"] = "MEBUFFRC",
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
			elseif actionID == 95 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 1,
["resource"] = "MEBUFFRC",
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
			end
		end
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 9,
["parameter2"] = 69,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = -1,
["parameter2"] = classSpellLevel,
["special"] = classSpellLevel,
["savingthrow"] = 0x2000000,
["resource"] = "EXMODMEM",
["vvcresource"] = spellRES,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = newTiming,
["duration"] = special,
["parameter3"] = spellSchool,
["savingthrow"] = 0x4000000,
["vvcresource"] = spellRES,
["resource2"] = parent_resource,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = IEex_GetActorStat(sourceID, casterClass + 95) + (casterClass * 0x100),
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 172,
["target"] = 2,
["timing"] = 0,
["duration"] = special,
["resource"] = "MESPLSEQ",
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 172,
["target"] = 2,
["timing"] = 0,
["duration"] = special,
["resource"] = parent_resource .. "D",
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 172,
["target"] = 2,
["timing"] = 0,
["duration"] = special,
["resource"] = parent_resource .. "P",
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 172,
["target"] = 2,
["timing"] = 0,
["duration"] = special,
["resource"] = parent_resource .. "S",
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 172,
["target"] = 2,
["timing"] = 0,
["duration"] = special,
["resource"] = parent_resource .. "T",
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 171,
["target"] = 2,
["timing"] = 0,
["duration"] = special,
["resource"] = internalContingencyRES,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		if newTiming == 0 then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 172,
["target"] = 2,
["timing"] = 4,
["duration"] = special,
["resource"] = internalContingencyRES,
["parent_resource"] = "MESPLSER",
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		end
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55597,
["source_id"] = sourceID
})
	end
end

IEex_AddActionHookOpcode("MESPLSEQ")

function MESPLSE2(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local spellRES = ""
	local abilityTarget = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local spellList = {}
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
		if theopcode == 0 and bit.band(thesavingthrow, 0x4000000) > 0 and theparent_resource == parent_resource then
			table.insert(spellList, {IEex_ReadLString(eData + 0x70, 8), IEex_ReadDword(eData + 0xC8)})
			IEex_WriteDword(eData + 0x114, 1)
		end
	end)
	local sourceX, sourceY = IEex_GetActorLocation(sourceID)
	local targetX, targetY = IEex_GetActorLocation(targetID)
--	local distance = math.floor(((((sourceX - targetX) / 16) ^ 2) + (((sourceY - targetY) / 12) ^ 2)) ^ .5) - 2
	for i = 1, #spellList, 1 do
		local resWrapper = IEex_DemandRes(spellList[i][1], "SPL")
		local projectile = 0
		local range = 1
		local target = 1
		if resWrapper:isValid() then
			local spellData = resWrapper:getData()
			target = IEex_ReadByte(spellData + 0x8E, 0x0)
			range = IEex_ReadWord(spellData + 0x90, 0x0)
			projectile = IEex_ReadWord(spellData + 0xA8, 0x0) - 1
			IEex_SetToken("EXACVAL1", IEex_FetchString(IEex_ReadDword(spellData + 0x8)))
		end
		resWrapper:free()
		local newTargetID = targetID
		local newTargetX, newTargetY = IEex_GetActorLocation(newTargetID)
		if target == 4 or target == 5 then
			newTargetID = sourceID
			if target == 5 then
				newTargetX = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0x6)
				newTargetY = IEex_ReadDword(IEex_GetActorShare(sourceID) + 0xA)
			end
		end
		if abilityTarget == 4 then
			newTargetX = IEex_ReadDword(effectData + 0x84)
			newTargetY = IEex_ReadDword(effectData + 0x88)
		end
		local distance = math.floor(((((sourceX - newTargetX) / 16) ^ 2) + (((sourceY - newTargetY) / 12) ^ 2)) ^ .5) - 2
		if distance <= range or target == 5 then
			if target ~= 4 then
				IEex_ApplyEffectToActor(newTargetID, {
["opcode"] = 146,
["target"] = 2,
["timing"] = 9,
["parameter1"] = bit.band(spellList[i][2], 0xFF),
["parameter2"] = 1,
["savingthrow"] = 0x10000,
["resource"] = spellList[i][1],
["parent_resource"] = spellList[i][1],
["source_x"] = sourceX,
["source_y"] = sourceY,
["target_x"] = newTargetX,
["target_y"] = newTargetY,
["casterlvl"] = spellList[i][2],
["source_id"] = sourceID
})
			else
				IEex_ApplyEffectToActor(newTargetID, {
["opcode"] = 148,
["target"] = 2,
["timing"] = 9,
["parameter1"] = bit.band(spellList[i][2], 0xFF),
["parameter2"] = 1,
["savingthrow"] = 0x10000,
["resource"] = spellList[i][1],
["parent_resource"] = spellList[i][1],
["source_x"] = sourceX,
["source_y"] = sourceY,
["target_x"] = newTargetX,
["target_y"] = newTargetY,
["casterlvl"] = spellList[i][2],
["source_id"] = sourceID
})
			end
		end
	end

	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 0,
["resource"] = string.sub(parent_resource, 1, (#parent_resource - 1)),
["parent_resource"] = parent_resource,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})

	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 172,
["target"] = 2,
["timing"] = 0,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
	IEex_WriteDword(effectData + 0x110, 1)
end

function MEBRDSEQ(originatingEffectData, actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	local numSpells = IEex_ReadWord(originatingEffectData + 0x18, 0x0)
	local maxSpellLevel = IEex_ReadWord(originatingEffectData + 0x1A, 0x0)
	if maxSpellLevel == 0 then
		maxSpellLevel = 9
	end
	local special = IEex_ReadDword(originatingEffectData + 0x44)
	if numSpells <= 0 then return end
	if actionID == 31 or actionID == 95 or actionID == 113 or actionID == 114 or actionID == 181 or actionID == 191 or actionID == 192 then
		
		local spellRES = IEex_GetActorSpellRES(sourceID)
		local resWrapper = IEex_DemandRes(spellRES, "SPL")
		if resWrapper:isValid() then
			local spellData = resWrapper:getData()
			IEex_SetToken("EXACVAL1", IEex_FetchString(IEex_ReadDword(spellData + 0x8)))
		end
		resWrapper:free()
		local casterClass = IEex_ReadSignedByte(creatureData + 0x530, 0x0)
		local casterDomain = IEex_ReadSignedByte(creatureData + 0x531, 0x0)
		if casterDomain == -1 then
			casterDomain = 0
		end
		local casterClass = IEex_ReadByte(originatingEffectData + 0xC5, 0x0)
		if casterClass ~= 2 then return end
		local classSpellLevel = IEex_ReadSignedByte(creatureData + 0x534, 0x0)
		if classSpellLevel <= 0 then
			classSpellLevel = IEex_GetClassSpellLevel(sourceID, casterClass, spellRES)
		end
		if classSpellLevel > maxSpellLevel or classSpellLevel == 0 then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55594,
["source_id"] = sourceID
})
			return
		end
		numSpells = numSpells - 1
		IEex_WriteWord(originatingEffectData + 0x18, numSpells)
		local casterlvl = IEex_ReadDword(originatingEffectData + 0xC4)
		local parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
		local internalContingencyRES = parent_resource .. "S"
		if #internalContingencyRES > 8 then
			internalContingencyRES = "MEBRDSEQ"
		end
		IEex_SetActionID(actionData, 0)
		local timing = IEex_ReadDword(originatingEffectData + 0x20)
		local duration = IEex_ReadDword(originatingEffectData + 0x24)
		local time_applied = IEex_ReadDword(originatingEffectData + 0x68)
		if timing == 4096 then
			timing = 0
			duration = math.floor((duration - time_applied) / 15)
		end
		if IEex_GetGlobal("EX_Recording_Buffs") == 1 then
			if actionID == 31 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 0,
["resource"] = "MEBUFFRC",
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
			elseif actionID == 95 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 1,
["resource"] = "MEBUFFRC",
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
			end
		end
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 233,
["target"] = 2,
["timing"] = 9,
["parameter2"] = 69,
["parent_resource"] = parent_resource,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = -1,
["parameter2"] = classSpellLevel,
["special"] = classSpellLevel,
["savingthrow"] = 0x2000000,
["resource"] = "EXMODMEM",
["vvcresource"] = spellRES,
["parent_resource"] = parent_resource,
["casterlvl"] = IEex_GetActorStat(sourceID, casterClass + 95) + (casterClass * 0x100) + (casterDomain * 0x10000),
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["savingthrow"] = 0x10000000,
["vvcresource"] = spellRES,
["parent_resource"] = parent_resource,
["casterlvl"] = IEex_GetActorStat(sourceID, casterClass + 95) + (casterClass * 0x100),
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 0,
["resource"] = "MEBRDSER",
["parent_resource"] = parent_resource,
["casterlvl"] = IEex_GetActorStat(sourceID, casterClass + 95) + (casterClass * 0x100),
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter1"] = 1,
["parameter2"] = 224,
["savingthrow"] = 0x10000000,
["resource"] = internalContingencyRES,
["parent_resource"] = "MEBRDSER",
["casterlvl"] = IEex_GetActorStat(sourceID, casterClass + 95) + (casterClass * 0x100),
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 142,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["parameter2"] = 177,
["parent_resource"] = "MEBRDSER",
["casterlvl"] = IEex_GetActorStat(sourceID, casterClass + 95) + (casterClass * 0x100),
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55595,
["source_id"] = sourceID
})
	end
end

IEex_AddActionHookOpcode("MEBRDSEQ")

ex_songcasting_base_chance = 0
ex_songcasting_chance_per_level = 1
ex_songcasting_chance_doubled_for_first_level_spell = false
function MEBRDSE2(effectData, creatureData)
	IEex_WriteDword(effectData + 0x110, 1)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	local spellRES = ""
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local spellList = {}
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
		if theopcode == 0 and bit.band(thesavingthrow, 0x10000000) > 0 then
			table.insert(spellList, {IEex_ReadLString(eData + 0x70, 8), IEex_ReadDword(eData + 0xC8)})
		end
	end)
	local songcastingChance = ex_songcasting_base_chance + ex_songcasting_chance_per_level * IEex_GetActorStat(sourceID, 97)
	local songcastingRandom = math.random(100)
	for k, v in ipairs(spellList) do
		if songcastingChance >= songcastingRandom or (ex_songcasting_chance_doubled_for_first_level_spell and IEex_GetClassSpellLevel(sourceID, 2, v[1]) == 1 and (songcastingChance * 2) >= songcastingRandom) then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 288,
["target"] = 2,
["timing"] = 0,
["duration"] = 2,
["parameter2"] = 229,
["special"] = -1,
["resource"] = v[1],
["parent_resource"] = parent_resource,
["casterlvl"] = v[2],
["source_id"] = sourceID
})
		end
	end
end

ex_copy_spell_target_ability = {[0] = "USWI454D", [1] = "USWI454D", [2] = "USWI454D", [3] = "USWI454D", [4] = "USWI454P", [5] = "USWI454S", [6] = "USWI454D", [7] = "USWI454S", [99] = "USWI454T"}
function MECOPYSP(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if targetID == sourceID or not IEex_IsSprite(sourceID, false) then return end
	local maxSpellLevel = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterlvl = IEex_ReadDword(effectData + 0xC4)
	local actionID = IEex_ReadWord(creatureData + 0x476, 0x0)
	IEex_SetToken("EXCPNAM1", IEex_GetActorName(targetID))
	if actionID == 31 or actionID == 95 or actionID == 191 or actionID == 192 then
		local spellRES = IEex_GetActorSpellRES(targetID)
		if ex_true_spell[spellRES] ~= nil then
			spellRES = ex_true_spell[spellRES]
		end
		if ex_no_copy_spell_list[spellRES] then return end
		local resWrapper = IEex_DemandRes(spellRES, "SPL")
		local spellTarget = 1
		local spellType = 1
		local spellRange = 1
		local baseSpellLevel = 0
		if resWrapper:isValid() then
			local spellData = resWrapper:getData()
			spellType = IEex_ReadWord(spellData + 0x1C, 0x0)
			spellTarget = IEex_ReadByte(spellData + 0x8E, 0x0)
			spellRange = IEex_ReadWord(spellData + 0x90, 0x0)
			baseSpellLevel = IEex_ReadDword(spellData + 0x34)
			IEex_SetToken("EXCPVAL1", IEex_FetchString(IEex_ReadDword(spellData + 0x8)))
		end
		resWrapper:free()
		local casterClass = IEex_ReadSignedByte(creatureData + 0x530, 0x0)
		local classSpellLevel = IEex_ReadSignedByte(creatureData + 0x534, 0x0)
		if classSpellLevel <= 0 then
			classSpellLevel = IEex_GetClassSpellLevel(targetID, casterClass, spellRES)
		end
		if classSpellLevel <= 0 then
			classSpellLevel = baseSpellLevel
		end
		if spellType < 1 or spellType > 2 or classSpellLevel <= 0 or ex_copy_spell_target_ability[spellTarget] == nil then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55582,
["source_id"] = sourceID
})
		elseif classSpellLevel > maxSpellLevel then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55581,
["source_id"] = sourceID
})
		end
		if spellType < 1 or spellType > 2 or classSpellLevel <= 0 or classSpellLevel > maxSpellLevel or ex_copy_spell_target_ability[spellTarget] == nil then return end
		local internalContingencyRES = ex_copy_spell_target_ability[spellTarget]
		if spellTarget == 1 and spellRange <= 1 then
			internalContingencyRES = ex_copy_spell_target_ability[99]
		end
		if IEex_GetGlobal("EX_Recording_Buffs") == 1 then
			if actionID == 31 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 0,
["resource"] = "MEBUFFRC",
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
			elseif actionID == 95 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 1,
["resource"] = "MEBUFFRC",
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
			end
		end
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55583,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = internalContingencyRES,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = 9,
["savingthrow"] = 0x8000000,
["vvcresource"] = spellRES,
["resource2"] = parent_resource,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = IEex_ReadByte(effectData + 0xC4, 0x0) + casterClass * 0x100,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 172,
["target"] = 2,
["timing"] = 9,
["resource"] = internalContingencyRES,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 171,
["target"] = 2,
["timing"] = 9,
["resource"] = internalContingencyRES,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
	else
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55580,
["source_id"] = sourceID
})
	end
end

function MECOPYS2(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local spellTarget = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterClass = 0
	local casterLevel = 1
	local spellRES = ""
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
		if theopcode == 0 and bit.band(thesavingthrow, 0x8000000) > 0 and theparent_resource == parent_resource then
			spellRES = IEex_ReadLString(eData + 0x70, 8)
			casterLevel = IEex_ReadByte(eData + 0xC8, 0x0)
			casterClass = IEex_ReadByte(eData + 0xC9, 0x0)
		end
	end)
	if spellRES == "" then return end
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = parent_resource,
["source_id"] = sourceID
})
	if spellTarget == 4 then
		local targetX = IEex_ReadDword(effectData + 0x84)
		local targetY = IEex_ReadDword(effectData + 0x88)
		local newDirection = IEex_GetActorRequiredDirection(sourceID, targetX, targetY)
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = newDirection,
["resource"] = "MEFACE",
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 148,
["target"] = 2,
["timing"] = 9,
["parameter1"] = casterLevel,
["savingthrow"] = 0x10000,
["resource"] = spellRES,
["target_x"] = targetX,
["target_y"] = targetY,
["casterlvl"] = casterLevel + casterClass * 0x100,
["source_id"] = sourceID
})
	else
		local targetX = IEex_ReadDword(creatureData + 0x6)
		local targetY = IEex_ReadDword(creatureData + 0xA)
		if targetID ~= sourceID then
			local newDirection = IEex_GetActorRequiredDirection(sourceID, targetX, targetY)
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = newDirection,
["resource"] = "MEFACE",
["source_id"] = sourceID
})
		end
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 146,
["target"] = 2,
["timing"] = 9,
["parameter1"] = casterLevel,
["savingthrow"] = 0x10000,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterLevel + casterClass * 0x100,
["source_id"] = sourceID
})
	end
end

ex_imbue_allowed_schools = {[0] = false, [1] = true, [2] = true, [3] = true, [4] = false, [5] = false, [6] = false, [7] = false, [8] = false, [9] = false, }
ex_imbue_spell_target_ability = {[0] = "USWI456D", [1] = "USWI456D", [2] = "USWI456D", [3] = "USWI456D", [4] = "USWI456P", [5] = "USWI456S", [6] = "USWI456D", [7] = "USWI456S", [99] = "USWI456T"}
function MEIMBUSP(originatingEffectData, actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	local numSpells = IEex_ReadWord(originatingEffectData + 0x18, 0x0)
	local maxSpellLevel = IEex_ReadWord(originatingEffectData + 0x1A, 0x0)
	if numSpells == 0 then
		numSpells = 1
	end
	if maxSpellLevel == 0 then
		maxSpellLevel = 9
	end
	local special = IEex_ReadDword(originatingEffectData + 0x44)
	if numSpells <= 0 then return end
	if actionID == 31 or actionID == 95 or actionID == 113 or actionID == 114 or actionID == 181 or actionID == 191 or actionID == 192 then
		local targetID = 0
		local parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
		IEex_IterateActorEffects(sourceID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local thesavingthrow = IEex_ReadDword(eData + 0x40)
			local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
			if theopcode == 0 and bit.band(thesavingthrow, 0x200000) > 0 and theparent_resource == parent_resource then
				targetID = IEex_Helper_GetBridge("IEex_ConstantID", IEex_ReadDword(eData + 0x64))
			end
		end)
		if targetID == 0 or targetID == nil then return end
		local spellRES = IEex_GetActorSpellRES(sourceID)
		if ex_true_spell[spellRES] ~= nil then
			spellRES = ex_true_spell[spellRES]
		end
		if ex_no_imbue_spell_list[spellRES] then return end
		local school = 0
		local resWrapper = IEex_DemandRes(spellRES, "SPL")
		local spellTarget = 1
		local spellType = 1
		local spellRange = 1
		local baseSpellLevel = 0
		if resWrapper:isValid() then
			local spellData = resWrapper:getData()
			spellType = IEex_ReadWord(spellData + 0x1C, 0x0)
			spellTarget = IEex_ReadByte(spellData + 0x8E, 0x0)
			spellRange = IEex_ReadWord(spellData + 0x90, 0x0)
			school = IEex_ReadByte(spellData + 0x25, 0x0)
			baseSpellLevel = IEex_ReadDword(spellData + 0x34)
			IEex_SetToken("EXACVAL1", IEex_FetchString(IEex_ReadDword(spellData + 0x8)))
		end
		resWrapper:free()
		if ex_trueschool[spellRES] ~= nil then
			school = ex_trueschool[spellRES]
		end
		if not ex_imbue_allowed_schools[school] then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55592,
["source_id"] = sourceID
})
			return
		end
		local casterClass = IEex_ReadSignedByte(creatureData + 0x530, 0x0)
		local casterDomain = IEex_ReadSignedByte(creatureData + 0x531, 0x0)
		if casterDomain == -1 then
			casterDomain = 0
		end
		local classSpellLevel = IEex_ReadSignedByte(creatureData + 0x534, 0x0)
		local casterlvl = IEex_ReadDword(originatingEffectData + 0xC4)
		if classSpellLevel <= 0 then
			classSpellLevel = IEex_GetClassSpellLevel(sourceID, IEex_ReadByte(originatingEffectData + 0xC5, 0x0), spellRES)
		end
		if classSpellLevel > maxSpellLevel then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55591,
["source_id"] = sourceID
})
			return
		elseif classSpellLevel == 0 then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55592,
["source_id"] = sourceID
})
			return
		end
		local internalContingencyRES = ex_imbue_spell_target_ability[spellTarget]
		if spellTarget == 1 and spellRange <= 1 then
			internalContingencyRES = ex_imbue_spell_target_ability[99]
		end
		if internalContingencyRES == nil then return end
		numSpells = numSpells - 1
		IEex_WriteWord(originatingEffectData + 0x18, numSpells)
		IEex_SetActionID(actionData, 0)
		local timing = IEex_ReadDword(originatingEffectData + 0x20)
		local duration = IEex_ReadDword(originatingEffectData + 0x24)
		local time_applied = IEex_ReadDword(originatingEffectData + 0x68)
		if timing == 4096 then
			timing = 0
			duration = math.floor((duration - time_applied) / 15)
		end
		if IEex_GetGlobal("EX_Recording_Buffs") == 1 then
			if actionID == 31 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 0,
["resource"] = "MEBUFFRC",
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
			elseif actionID == 95 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 1,
["resource"] = "MEBUFFRC",
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
			end
		end
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = -1,
["parameter2"] = classSpellLevel,
["special"] = classSpellLevel,
["savingthrow"] = 0x2000000,
["resource"] = "EXMODMEM",
["vvcresource"] = spellRES,
["parent_resource"] = parent_resource,
["casterlvl"] = IEex_ReadByte(originatingEffectData + 0xC4, 0x0) + casterClass * 0x100 + casterDomain * 0x10000,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55593,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = internalContingencyRES,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 0,
["target"] = 2,
["timing"] = timing,
["duration"] = duration,
["savingthrow"] = 0x20000000,
["vvcresource"] = spellRES,
["resource2"] = parent_resource,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = IEex_ReadByte(originatingEffectData + 0xC4, 0x0) + casterClass * 0x100,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 172,
["target"] = 2,
["timing"] = 9,
["resource"] = internalContingencyRES,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 172,
["target"] = 2,
["timing"] = 4,
["duration"] = duration,
["resource"] = internalContingencyRES,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 171,
["target"] = 2,
["timing"] = 9,
["resource"] = internalContingencyRES,
["parent_resource"] = internalContingencyRES,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
	end
end

IEex_AddActionHookOpcode("MEIMBUSP")

function MEIMBUS2(effectData, creatureData)
	if IEex_CheckForEffectRepeat(effectData, creatureData) then return end
	local targetID = IEex_GetActorIDShare(creatureData)
	local sourceID = IEex_ReadDword(effectData + 0x10C)
	if not IEex_IsSprite(sourceID, false) then return end
	local spellTarget = IEex_ReadDword(effectData + 0x44)
	local parent_resource = IEex_ReadLString(effectData + 0x90, 8)
	local casterClass = 0
	local casterLevel = 1
	local spellRES = ""
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
		if theopcode == 0 and bit.band(thesavingthrow, 0x20000000) > 0 and theparent_resource == parent_resource then
			spellRES = IEex_ReadLString(eData + 0x70, 8)
			casterLevel = IEex_ReadByte(eData + 0xC8, 0x0)
			casterClass = IEex_ReadByte(eData + 0xC9, 0x0)
		end
	end)
	if spellRES == "" then return end
	IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = parent_resource,
["source_id"] = sourceID
})
	if spellTarget == 4 then
		local targetX = IEex_ReadDword(effectData + 0x84)
		local targetY = IEex_ReadDword(effectData + 0x88)
		local newDirection = IEex_GetActorRequiredDirection(sourceID, targetX, targetY)
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = newDirection,
["resource"] = "MEFACE",
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 148,
["target"] = 2,
["timing"] = 9,
["parameter1"] = casterLevel,
["savingthrow"] = 0x10000,
["resource"] = spellRES,
["target_x"] = targetX,
["target_y"] = targetY,
["casterlvl"] = casterLevel + casterClass * 0x100,
["source_id"] = sourceID
})
	else
		local targetX = IEex_ReadDword(creatureData + 0x6)
		local targetY = IEex_ReadDword(creatureData + 0xA)
		if targetID ~= sourceID then
			local newDirection = IEex_GetActorRequiredDirection(sourceID, targetX, targetY)
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = newDirection,
["resource"] = "MEFACE",
["source_id"] = sourceID
})
		end
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 146,
["target"] = 2,
["timing"] = 9,
["parameter1"] = casterLevel,
["savingthrow"] = 0x10000,
["resource"] = spellRES,
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterLevel + casterClass * 0x100,
["source_id"] = sourceID
})
	end
end

function MESPLSTF(originatingEffectData, actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	local numSpells = IEex_ReadWord(originatingEffectData + 0x18, 0x0)
	local maxSpellLevel = IEex_ReadWord(originatingEffectData + 0x1A, 0x0)
	local numCharges = IEex_ReadSignedWord(originatingEffectData + 0x44, 0x0)
	if maxSpellLevel == 0 then
		maxSpellLevel = 1
	end
	if numSpells <= 0 then return end
	if actionID == 31 or actionID == 95 or actionID == 113 or actionID == 114 or actionID == 181 or actionID == 191 or actionID == 192 then
		local parent_resource = IEex_ReadLString(originatingEffectData + 0x90, 8)
		local spellRES = IEex_GetActorSpellRES(sourceID)
		if ex_true_spell[spellRES] ~= nil then
			spellRES = ex_true_spell[spellRES]
		end
		local resWrapper = IEex_DemandRes(spellRES, "SPL")
		local spellTarget = 1
		local spellType = 1
		local spellRange = 1
		local baseSpellLevel = 0
		if resWrapper:isValid() then
			local spellData = resWrapper:getData()
			spellType = IEex_ReadWord(spellData + 0x1C, 0x0)
			spellTarget = IEex_ReadByte(spellData + 0x8E, 0x0)
			spellRange = IEex_ReadWord(spellData + 0x90, 0x0)
			baseSpellLevel = IEex_ReadDword(spellData + 0x34)
			IEex_SetToken("EXACVAL1", IEex_FetchString(IEex_ReadDword(spellData + 0x8)))
		else
			resWrapper:free()
			return
		end
		resWrapper:free()
		local casterClass = IEex_ReadSignedByte(creatureData + 0x530, 0x0)
		local casterDomain = IEex_ReadSignedByte(creatureData + 0x531, 0x0)
		if casterDomain == -1 then
			casterDomain = 0
		end
		local classSpellLevel = IEex_ReadSignedByte(creatureData + 0x534, 0x0)
		local casterlvl = IEex_ReadDword(originatingEffectData + 0xC4)
		if classSpellLevel <= 0 then
			classSpellLevel = IEex_GetClassSpellLevel(sourceID, IEex_ReadByte(originatingEffectData + 0xC5, 0x0), spellRES)
		end
		if classSpellLevel > maxSpellLevel then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55584,
["source_id"] = sourceID
})
			return
		elseif classSpellLevel == 0 then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55585,
["source_id"] = sourceID
})
			return
		elseif IEex_GetItemSlotRES(sourceID, 44 + IEex_ReadByte(creatureData + 0x4C68, 0x0) * 2) ~= "" then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55382,
["source_id"] = sourceID
})
			return
		end

		local internalContingencyRES = spellRES .. "S"
		local resWrapper = IEex_DemandRes(internalContingencyRES, "ITM")
		if not resWrapper:isValid() then
			IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55587,
["source_id"] = sourceID
})
			resWrapper:free()
			return
		end
		resWrapper:free()
		numSpells = numSpells - 1
		IEex_WriteWord(originatingEffectData + 0x18, numSpells)
		IEex_SetActionID(actionData, 0)
		local timing = IEex_ReadDword(originatingEffectData + 0x20)
		local duration = IEex_ReadDword(originatingEffectData + 0x24)
		local time_applied = IEex_ReadDword(originatingEffectData + 0x68)
		if timing == 4096 then
			timing = 0
			duration = math.floor((duration - time_applied) / 15)
		end
		if numCharges == 0 then
			numCharges = IEex_ReadByte(originatingEffectData + 0xC4, 0x0)
		end
		if IEex_GetGlobal("EX_Recording_Buffs") == 1 then
			if actionID == 31 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 0,
["resource"] = "MEBUFFRC",
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
			elseif actionID == 95 then
				IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["special"] = 1,
["resource"] = "MEBUFFRC",
["parent_resource"] = spellRES,
["source_id"] = sourceID
})
			end
		end
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 254,
["target"] = 2,
["timing"] = 9,
["resource"] = parent_resource,
["parent_resource"] = parent_resource,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 500,
["target"] = 2,
["timing"] = 0,
["parameter1"] = -1,
["parameter2"] = classSpellLevel,
["special"] = classSpellLevel,
["savingthrow"] = 0x2000000,
["resource"] = "EXMODMEM",
["vvcresource"] = spellRES,
["parent_resource"] = parent_resource,
["casterlvl"] = IEex_ReadByte(originatingEffectData + 0xC4, 0x0) + casterClass * 0x100 + casterDomain * 0x10000,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 111,
["target"] = 2,
["timing"] = 0,
["duration"] = duration,
["parameter1"] = numCharges,
["resource"] = internalContingencyRES,
["parent_resource"] = parent_resource,
["casterlvl"] = casterlvl,
["source_id"] = sourceID
})
		IEex_ApplyEffectToActor(sourceID, {
["opcode"] = 139,
["target"] = 2,
["timing"] = 9,
["parameter1"] = ex_tra_55588,
["source_id"] = sourceID
})
		local slotData = IEex_ReadDword(creatureData + 0x4B80)
		if slotData > 0 then
			IEex_WriteWord(slotData + 0x18, numCharges)
		end
	end
end

IEex_AddActionHookOpcode("MESPLSTF")

function MEBOULDR(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	local spellActions = {
		[31]  = 95 , -- Spell            => SpellPoint
		[113] = 114, -- ForceSpell       => ForceSpellPoint
		[181] = 114, -- ReallyForceSpell => ForceSpellPoint
		[191] = 192, -- SpellNoDec       => SpellPointNoDec
	}
	
	if spellActions[actionID] ~= nil and ex_due_south_spells[IEex_GetActorSpellRES(sourceID)] ~= nil then
		local sourceX, sourceY = IEex_GetActorLocation(sourceID)
		local areaRES = ""
		if IEex_ReadDword(creatureData + 0x12) > 0 then
			areaRES = IEex_ReadLString(IEex_ReadDword(creatureData + 0x12), 8)
		end
		local resWrapper = IEex_DemandRes(areaRES .. "SR", "BMP")
		if resWrapper:isValid() then
			local bitmapData = resWrapper:getData()
			local fileSize = IEex_ReadDword(bitmapData + 0x2)
			local dataOffset = IEex_ReadDword(bitmapData + 0xA)
			local bitmapX = IEex_ReadDword(bitmapData + 0x12)
			local bitmapY = IEex_ReadDword(bitmapData + 0x16)
			local padding = 4 - (bitmapX / 2) % 4
			if padding == 4 then
				padding = 0
			end
			local areaX = bitmapX * 16
			local areaY = bitmapY * 12
			local pixelSizeX = 16
			local pixelSizeY = 12
			local current = 0
			local currentA = 0
			local currentB = 0
			local currentX = 0
			local currentY = 0
			local x = math.floor(sourceX / pixelSizeX)
			local y = bitmapY - math.floor(sourceY / pixelSizeY) - 2
			if y < 1 then
				y = 1
			end
			local trueBitmapX = math.floor(bitmapX / 2) + padding
			while y >= 2 do
				current = IEex_ReadByte(bitmapData + dataOffset + y * trueBitmapX + math.floor(x / 2), 0x0)
				if ex_default_terrain_table_1[math.floor(current / 16) + 1] == -1 and ex_default_terrain_table_1[(current % 16) + 1] == -1 then
					break
				end
				y = y - 1
			end
			IEex_WriteWord(creatureData + 0x476, spellActions[actionID])
			IEex_WriteDword(creatureData + 0x540, sourceX)
			IEex_WriteDword(creatureData + 0x544, (bitmapY - y) * pixelSizeY)
		end
		resWrapper:free()
	end
end

IEex_AddActionHookGlobal("MEBOULDR")

function MEONREST(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	if actionID ~= 96 then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	IEex_IterateActorEffects(sourceID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local theparameter2 = IEex_ReadDword(eData + 0x20)
		if theopcode == 288 and theparameter2 == 197 then
			IEex_WriteDword(eData + 0x60, 0)
		end
	end)
end

IEex_AddActionHookGlobal("MEONREST")

function MEFEATSC(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	if actionID ~= 316 then return end
	local targetID = IEex_GetActionObjectID(actionData)
	local targetShare = IEex_GetActorShare(targetID)
	local featID = IEex_GetActionInt1(actionData)
	local newFeatCount = IEex_GetSpriteFeatCount(targetShare, featID) + 1
	if IEex_GetSpriteFeatIncrementable(targetShare, featID, true) then
		local featSpellRES = "FE_" .. featID .. "_" .. (newFeatCount)
		IEex_ApplyEffectToActor(targetID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 9,
["resource"] = featSpellRES,
["parent_resource"] = featSpellRES,
["source_id"] = targetID
})
		if featID <= 74 and not IEex_Feats_DefaultMaxPips[featID] then
			IEex_SetSpriteFeatCountStat(targetShare, featID, newFeatCount)
		end
	end
end

IEex_AddActionHookGlobal("MEFEATSC")

function METELATO(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	if actionID ~= 48 then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	IEex_PreventMovingAttacksOfOpportunity(sourceID, 10)
	local actionX = IEex_ReadDword(creatureData + 0x540)
	local actionY = IEex_ReadDword(creatureData + 0x544)
	IEex_WriteDword(creatureData + 0x556E, actionX)
	IEex_WriteDword(creatureData + 0x5572, actionY)
end

IEex_AddActionHookGlobal("METELATO")

function MEGENTOK(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	if actionID ~= 8 and actionID ~= 137 and actionID ~= 139 and actionID ~= 198 then return end
	local sourceID = IEex_GetActorIDShare(creatureData)
	local playerID = IEex_ReadDword(creatureData + 0x4BE)
	if actionID == 139 then
		playerID = sourceID
	end
	if not IEex_IsSprite(playerID, true) then
		 for i = 0, 5, 1 do
			if IEex_IsSprite(IEex_GetActorIDCharacter(i), false) then
				playerID = IEex_GetActorIDCharacter(i)
				break;
			end
		 end
		 if not IEex_IsSprite(playerID, true) then return end
	end
	local playerGender = IEex_ReadSignedByte(IEex_GetActorShare(playerID) + 0x34, 0x0)
	if playerGender < 1 or playerGender > 2 then
		playerGender = 1
	end
	for key, value in pairs(ex_dynamic_gender_tokens) do
		IEex_SetToken(key, IEex_FetchString(value[playerGender]))
	end
end

if ex_enable_dynamic_gender_tokens then
	IEex_AddActionHookGlobal("MEGENTOK")
	IEex_AddScreenEffectsGlobal("MEGENTOE", function(effectData, creatureData)
		local targetID = IEex_GetActorIDShare(creatureData)
		local opcode = IEex_ReadDword(effectData + 0xC)
		if opcode ~= 139 and opcode ~= 283 then return false end
		local playerGender = IEex_ReadSignedByte(creatureData + 0x34, 0x0)
		if playerGender < 1 or playerGender > 2 then
			playerGender = 1
		end
		for key, value in pairs(ex_dynamic_gender_tokens) do
			IEex_SetToken(key, IEex_FetchString(value[playerGender]))
		end
	end)
end

function MERECACT(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	if actionID == 31 or actionID == 113 or actionID == 181 or actionID == 191 then
		local targetID = IEex_ReadDword(creatureData + 0x4BE)
		local targetX, targetY = IEex_GetActorLocation(targetID)
		local spellRES = IEex_GetActorSpellRES(sourceID)
		IEex_Helper_SetBridge("IEex_RecordSpell", sourceID, "actionID", actionID)
		IEex_Helper_SetBridge("IEex_RecordSpell", sourceID, "targetID", targetID)
		IEex_Helper_SetBridge("IEex_RecordSpell", sourceID, "targetX", targetX)
		IEex_Helper_SetBridge("IEex_RecordSpell", sourceID, "targetY", targetY)
		IEex_Helper_SetBridge("IEex_RecordSpell", sourceID, "spellRES", spellRES)
	elseif actionID == 95 or actionID == 114 or actionID == 192 then
		local targetID = 0
		local targetX = IEex_ReadDword(creatureData + 0x540)
		local targetY = IEex_ReadDword(creatureData + 0x544)
		local spellRES = IEex_GetActorSpellRES(sourceID)
		IEex_Helper_SetBridge("IEex_RecordSpell", sourceID, "actionID", actionID)
		IEex_Helper_SetBridge("IEex_RecordSpell", sourceID, "targetID", targetID)
		IEex_Helper_SetBridge("IEex_RecordSpell", sourceID, "targetX", targetX)
		IEex_Helper_SetBridge("IEex_RecordSpell", sourceID, "targetY", targetY)
		IEex_Helper_SetBridge("IEex_RecordSpell", sourceID, "spellRES", spellRES)
	elseif actionID == 3 or actionID == 98 or actionID == 105 or actionID == 134 then
		local targetID = IEex_ReadDword(creatureData + 0x4BE)
		local weaponInfo = IEex_ReadDword(creatureData + 0x4AD8 + IEex_ReadByte(creatureData + 0x4BA4, 0x0) * 0x4)
		local weaponRES = ""
		local weaponHeader = IEex_ReadByte(creatureData + 0x4BA6, 0x0)
		if weaponInfo > 0 then
			weaponRES = IEex_ReadLString(weaponInfo + 0xC, 8)
		end
		IEex_Helper_SetBridge("IEex_RecordAttack", sourceID, "actionID", actionID)
		IEex_Helper_SetBridge("IEex_RecordAttack", sourceID, "targetID", targetID)
		IEex_Helper_SetBridge("IEex_RecordAttack", sourceID, "weaponRES", weaponRES)
		IEex_Helper_SetBridge("IEex_RecordAttack", sourceID, "weaponHeader", weaponHeader)	
	end
end

IEex_AddActionHookGlobal("MERECACT")

function MESWTARG(actionData, creatureData)
	local actionID = IEex_GetActionID(actionData)
	local sourceID = IEex_GetActorIDShare(creatureData)
	local targetID = IEex_ReadDword(creatureData + 0x4BE)
--	if actionID == 3 or actionID == 105 or actionID == 134 then
--		IEex_Search(IEex_GetActorIDPortrait(1), creatureData, 0x600, false)
--	end
	if not IEex_GetActorSpellState(targetID, 219) or not IEex_IsSprite(sourceID, false) or IEex_ReadByte(creatureData + 0x838, 0x0) == 1 or IEex_CompareActorAllegiances(sourceID, targetID) == 1 or IEex_InCutsceneMode() or IEex_IsDialogWindowOpen() or actionID == 150 then return end
	local targetShare = IEex_GetActorShare(targetID)
	local ids = {}
	if IEex_ReadDword(creatureData + 0x12) > 0 then
		ids = IEex_GetIDArea(sourceID, 0x31)
	end
	local sourceX, sourceY = IEex_GetActorLocation(sourceID)
	local targetX, targetY = IEex_GetActorLocation(targetID)
	local targetDistance = IEex_GetDistance(sourceX, sourceY, targetX, targetY)
	if IEex_ReadDword(targetShare + 0x4BE) == sourceID and targetDistance < 100 then return end
	local closestDistance = 0x7FFFFFFF
	local closeTarget = {0, 0, 0}
	local farTarget = {0, 0, 0}
	for k, currentID in ipairs(ids) do
		local currentShare = IEex_GetActorShare(currentID)
		if currentShare > 0 then
			local currentX = IEex_ReadDword(currentShare + 0x6)
			local currentY = IEex_ReadDword(currentShare + 0xA)
			local currentDistance = IEex_GetDistance(sourceX, sourceY, currentX, currentY)
			local states = IEex_ReadDword(currentShare + 0x5BC)
			local animation = IEex_ReadDword(currentShare + 0x5C4)
			local cea = IEex_CompareActorAllegiances(targetID, currentID)
			if currentDistance < 500 and not IEex_GetActorSpellState(currentID, 219) and currentDistance > targetDistance and currentDistance < closestDistance and cea == 1 and animation >= 0x1000 and (animation < 0xD000 or animation >= 0xE000) and bit.band(states, 0x800) == 0 and IEex_ReadByte(currentShare + 0x838, 0x0) == 0 and ((IEex_GetActorState(currentID, 0x10) and IEex_ReadByte(currentShare + 0x8A0, 0x0) > 0) or not IEex_GetActorState(currentID, 0x10) or IEex_GetActorStat(sourceID, 81) > 0) then
				closestDistance = currentDistance
				farTarget = {currentID, currentX, currentY}
			end
		end
	end
	if farTarget[1] ~= 0 then
		IEex_WriteDword(creatureData + 0x25C, farTarget[1])
		IEex_WriteDword(creatureData + 0x34C, farTarget[1])
		IEex_WriteDword(creatureData + 0x4BE, farTarget[1])
	else
--[[
		closestDistance = 0x7FFFFFFF
		for k, currentID in ipairs(ids) do
			local currentShare = IEex_GetActorShare(currentID)
			if currentShare > 0 then
				local currentX = IEex_ReadDword(currentShare + 0x6)
				local currentY = IEex_ReadDword(currentShare + 0xA)
				local currentDistance = IEex_GetDistance(sourceX, sourceY, currentX, currentY)
				local states = IEex_ReadDword(currentShare + 0x5BC)
				local animation = IEex_ReadDword(currentShare + 0x5C4)
				local cea = IEex_CompareActorAllegiances(targetID, currentID)
				if IEex_CheckActorLOSObject(sourceID, currentID) and not IEex_GetActorSpellState(currentID, 219) and currentDistance < targetDistance and currentDistance < closestDistance and cea == 1 and animation >= 0x1000 and (animation < 0xD000 or animation >= 0xE000) and bit.band(states, 0x800) == 0 and IEex_ReadByte(currentShare + 0x838, 0x0) == 0 and (IEex_ReadByte(currentShare + 0x8A0, 0x0) > 0 or IEex_GetActorStat(sourceID, 81) > 0) then
					closestDistance = currentDistance
					closeTarget = {currentID, currentX, currentY}
				end
			end
		end
		if closeTarget[1] ~= 0 then
			IEex_WriteDword(creatureData + 0x4BE, closeTarget[1])
		end
--]]
	end
end

IEex_AddActionHookGlobal("MESWTARG")
--[[
Player1 = 1
Player2 = 2
Player3 = 3
Player4 = 4
Player5 = 5
Player6 = 6
Myself = 0x5C
LastMarkedObject = 0x34C

function IEex_GetBCSObjectID(actorID, BCSObject)
	if BCSObject >= 1 and BCSObject <= 6 then
		return IEex_GetActorIDCharacter(BCSObject - 1)
	else
		local creatureData = IEex_GetActorShare(actorID)
		if creatureData > 0 then
			return IEex_ReadDword(creatureData + BCSObject)
		end
	end
	return 0
end

function LastSeenBy(BCSObject)
	if BCSObject == Myself then
		return IEex_ReadDword(IEex_GetActorShare(IEex_Lua_ActorID) + 0x25C)
	else
		return IEex_ReadDword(IEex_GetActorShare(IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)) + 0x25C)
	end
end

function LastSummonerOf(BCSObject)
	if BCSObject == Myself then
		return IEex_ReadDword(IEex_GetActorShare(IEex_Lua_ActorID) + 0x72C)
	else
		return IEex_ReadDword(IEex_GetActorShare(IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)) + 0x72C)
	end
end
]]

Player1 = {1, nil}
Player2 = {2, nil}
Player3 = {3, nil}
Player4 = {4, nil}
Player5 = {5, nil}
Player6 = {6, nil}
Myself = {0x5C, nil}
LastTalkedToBy = {0x298, nil}
LastMarkedObject = {0x34C, nil}

function IEex_GetBCSObjectID(actorID, BCSObject)
	if BCSObject[1] >= 1 and BCSObject[1] <= 6 then
		return IEex_GetActorIDCharacter(BCSObject - 1)
	else
		local creatureData = IEex_GetActorShare(actorID)
		if BCSObject[2] ~= nil then
			actorID = BCSObject[2]
			creatureData = IEex_GetActorShare(actorID)
		end
		if creatureData > 0 then
			if BCSObject[1] == 0x72C then
				return IEex_GetActorSummonerID(actorID)
			else
				return IEex_ReadDword(creatureData + BCSObject[1])
			end
		end
	end
	return 0
end

function LastSeenBy(BCSObject)
	if BCSObject == Myself then
		return {0x25C, nil}
	else
		return {0x25C, IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)}
	end
end

function LastSummonerOf(BCSObject)
	if BCSObject == Myself then
		return {0x72C, nil}
	else
		return {0x72C, IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)}
	end
end

ex_ea_wildcards = {
[0] = {[0] = true, [1] = true, [2] = true, [3] = true, [4] = true, [5] = true, [6] = true, [7] = true, [28] = true, [29] = true, [30] = true, [31] = true, [126] = true, [128] = true, [199] = true, [200] = true, [201] = true, [202] = true, [255] = true},
[30] = {[0] = true, [2] = true, [3] = true, [4] = true, [5] = true, [6] = true, [7] = true, [28] = true, [29] = true, [30] = true},
[31] = {[0] = true, [1] = true, [31] = true, [126] = true, [128] = true, [200] = true, [201] = true, [202] = true, [255] = true},
[126] = {[0] = true, [1] = true, [2] = true, [3] = true, [4] = true, [5] = true, [6] = true, [7] = true, [28] = true, [29] = true, [30] = true, [31] = true, [126] = true, [128] = true, [199] = true, [200] = true, [201] = true, [202] = true, [255] = true},
[199] = {[0] = true, [1] = true, [2] = true, [3] = true, [4] = true, [5] = true, [6] = true, [7] = true, [28] = true, [29] = true, [30] = true, [126] = true, [128] = true, [199] = true},
[200] = {[0] = true, [200] = true, [201] = true, [202] = true, [255] = true}
}

function IEex_MatchAOE(minTargets, radius, check)
	local sourceID = IEex_Lua_ActorID
	local creatureData = IEex_GetActorShare(sourceID)
	if check["pconly"] == true then
		local numInParty = 0
		for i = 0, 5, 1 do
			if IEex_IsSprite(IEex_GetActorIDCharacter(i), false) then 
				numInParty = numInParty + 1
			end
		end
		if numInParty < minTargets then
			minTargets = numInParty
		end
	end
	if minTargets <= 0 then
		minTargets = 1
	end

	if check["cea"] == nil then
		check["cea"] = {-1, true}
	end

	if check["ea"] == nil then
		local allegiance = IEex_ReadByte(creatureData + 0x24, 0x0)
		local checkCEA = check["cea"]
		if checkCEA[1] == 0 or allegiance == 128 then
			check["ea"] = {0, checkCEA[2]}
		elseif allegiance <= 30 then	
			if checkCEA[1] == -1 then
				check["ea"] = {200, checkCEA[2]}
			elseif checkCEA[1] == 0 then
				check["ea"] = {128, checkCEA[2]}
			elseif checkCEA[1] == 1 then
				check["ea"] = {30, checkCEA[2]}
			end
		elseif allegiance >= 200 then
			if checkCEA[1] == -1 then
				check["ea"] = {30, checkCEA[2]}
			elseif checkCEA[1] == 0 then
				check["ea"] = {128, checkCEA[2]}
			elseif checkCEA[1] == 1 then
				check["ea"] = {200, checkCEA[2]}
			end
		end
	end



	local matchEA = {[check["ea"][1]] = true}
	if ex_ea_wildcards[check["ea"][1]] ~= nil then
		matchEA = ex_ea_wildcards[check["ea"][1]]
	end

	local ids = {}
	local areaData = IEex_ReadDword(creatureData + 0x12)
	IEex_IterateIDs(areaData, 0x31, function(currentID)
		local currentShare = IEex_GetActorShare(currentID)
		if IEex_IsSprite(currentID, false) and IEex_ReadByte(currentShare + 0x838, 0x0) == 0 and (matchEA[IEex_ReadByte(currentShare + 0x24, 0x0)] ~= nil) == check["ea"][2] and IEex_CheckActorLOSObject(sourceID, currentID) and IEex_CheckTarget(sourceID, currentID, check) then
			table.insert(ids, currentID)
		end
	end)
	local highestTargetCount = 0
	local highestTargetCountID = 0
	for k, id in ipairs(ids) do
		local targetCount = 1
		local targetX, targetY = IEex_GetActorLocation(id)
		IEex_IterateIDs(areaData, 0x31, function(currentID)
			local currentShare = IEex_GetActorShare(currentID)
			if IEex_IsSprite(currentID, false) and currentID ~= id and IEex_ReadByte(currentShare + 0x838, 0x0) == 0 then
				local currentX, currentY = IEex_GetActorLocation(currentID)
				local currentDistance = IEex_GetDistanceIsometric(targetX, targetY, currentX, currentY)
				if (currentDistance < radius or radius == -1) and (matchEA[IEex_ReadByte(currentShare + 0x24, 0x0)] ~= nil) == check["ea"][2] and IEex_CheckActorLOSObject(id, currentID) then
					if IEex_CheckTarget(sourceID, currentID, check) then
						targetCount = targetCount + 1
					end
				end
			end
		end)
		if targetCount > highestTargetCount then
			highestTargetCount = targetCount
			highestTargetCountID = id
		end
	end
	if highestTargetCount >= minTargets then
		IEex_WriteDword(creatureData + 0x34C, highestTargetCountID)
		return true
	else
		return false
	end
end

function IEex_MatchAOE_Self(minTargets, radius, check)
	local sourceID = IEex_Lua_ActorID
	local creatureData = IEex_GetActorShare(sourceID)
	if check["pconly"] == true then
		local numInParty = 0
		for i = 0, 5, 1 do
			if IEex_IsSprite(IEex_GetActorIDCharacter(i), false) then 
				numInParty = numInParty + 1
			end
		end
		if numInParty < minTargets then
			minTargets = numInParty
		end
	end
	if minTargets <= 0 then
		minTargets = 1
	end

	if check["cea"] == nil then
		check["cea"] = {-1, true}
	end

	if check["ea"] == nil then
		local allegiance = IEex_ReadByte(creatureData + 0x24, 0x0)
		local checkCEA = check["cea"]
		if checkCEA[1] == 0 or allegiance == 128 then
			check["ea"] = {0, checkCEA[2]}
		elseif allegiance <= 30 then	
			if checkCEA[1] == -1 then
				check["ea"] = {200, checkCEA[2]}
			elseif checkCEA[1] == 0 then
				check["ea"] = {128, checkCEA[2]}
			elseif checkCEA[1] == 1 then
				check["ea"] = {30, checkCEA[2]}
			end
		elseif allegiance >= 200 then
			if checkCEA[1] == -1 then
				check["ea"] = {30, checkCEA[2]}
			elseif checkCEA[1] == 0 then
				check["ea"] = {128, checkCEA[2]}
			elseif checkCEA[1] == 1 then
				check["ea"] = {200, checkCEA[2]}
			end
		end
	end



	local matchEA = {[check["ea"][1]] = true}
	if ex_ea_wildcards[check["ea"][1]] ~= nil then
		matchEA = ex_ea_wildcards[check["ea"][1]]
	end

	local ids = {}
	local areaData = IEex_ReadDword(creatureData + 0x12)
	local sourceX, sourceY = IEex_GetActorLocation(sourceID)
	local targetCount = 0
	IEex_IterateIDs(areaData, 0x31, function(currentID)
		local currentShare = IEex_GetActorShare(currentID)
		local currentX, currentY = IEex_GetActorLocation(currentID)
		local currentDistance = IEex_GetDistanceIsometric(sourceX, sourceY, currentX, currentY)
		if IEex_IsSprite(currentID, false) and IEex_ReadByte(currentShare + 0x838, 0x0) == 0 and (currentDistance < radius or radius == -1) and (matchEA[IEex_ReadByte(currentShare + 0x24, 0x0)] ~= nil) == check["ea"][2] and IEex_CheckActorLOSObject(sourceID, currentID) and IEex_CheckTarget(sourceID, currentID, check) then
			targetCount = targetCount + 1
		end
	end)
	if targetCount >= minTargets then
		return true
	else
		return false
	end
end

function IEex_CheckTarget(sourceID, currentID, check)
	local currentShare = IEex_GetActorShare(currentID)
	local states = bit.bor(IEex_ReadDword(currentShare + 0x434), IEex_ReadDword(currentShare + 0xB30))
	if check["pconly"] == true and not IEex_IsPartyMember(currentID) then return end

--	local ea = IEex_ReadByte(currentShare + 0x24, 0x0)
--	local matchEA = {[check["ea"][1]] = true}
--	if me_ea_wildcards[check["ea"][1]] ~= nil then
--		matchEA = me_ea_wildcards[check["ea"][1]]
--	end
--	if (matchEA[ea] ~= nil) ~= check["ea"][2] then return false end

	if check["general"] ~= nil then
		local general = IEex_ReadByte(currentShare + 0x25, 0x0)
		local hasOne = nil
		for i, iGeneral in ipairs(check["general"]) do
			if iGeneral[1] == general then
				if iGeneral[2] == true then
					hasOne = true
				else
					return false
				end
			elseif iGeneral[2] == true and hasOne == nil then
				hasOne = false
			end
		end
		if hasOne == false then return false end
	end
	if check["race"] ~= nil then
		local race = IEex_ReadByte(currentShare + 0x26, 0x0)
		local hasOne = nil
		for i, iRace in ipairs(check["race"]) do
			if iRace[1] == race then
				if iRace[2] == true then
					hasOne = true
				else
					return false
				end
			elseif iRace[2] == true and hasOne == nil then
				hasOne = false
			end
		end
		if hasOne == false then return false end
	end
	if check["alignment"] ~= nil then
		local alignment = IEex_ReadByte(currentShare + 0x35, 0x0)
		if (bit.band(check["alignment"][1], alignment) == check["alignment"][1]) ~= check["alignment"][2] then return false end
	end
	if check["stat"] ~= nil then
		for i, iStat in ipairs(check["stat"]) do
			local check_stat = IEex_GetActorStat(currentID, iStat[1])
			local check_value = iStat[2]
			local check_relation = iStat[3]
			if check_relation == 0 and check_stat > check_value then return false
			elseif check_relation == 1 and check_stat ~= check_value then return false
			elseif check_relation == 2 and check_stat >= check_value then return false
			elseif check_relation == 3 and check_stat <= check_value then return false
			elseif check_relation == 4 and check_stat < check_value then return false
			elseif check_relation == 5 and check_stat == check_value then return false
			elseif check_relation == 6 and bit.bor(check_stat, check_value) ~= check_value then return false
			elseif check_relation == 7 and bit.band(check_stat, check_value) < check_value then return false
			elseif check_relation == 8 and bit.band(check_stat, check_value) == 0 then return false
			elseif check_relation == 9 and bit.band(check_stat, check_value) > 0 then return false
			elseif check_relation == 10 and bit.bor(check_stat, check_value) <= check_value then return false
			elseif check_relation == 11 and bit.band(check_stat, check_value) >= check_value then return false
			end
		end
	end
	if check["state"] ~= nil then
		if (IEex_GetActorState(currentID, check["state"][1])) ~= check["state"][2] then return false end
	end
	if check["spellState"] ~= nil then
		for i, iSpellState in ipairs(check["spellState"]) do
			if (IEex_GetActorSpellState(currentID, iSpellState[1])) ~= iSpellState[2] then return false end
		end
	end
	if check["opcode"] ~= nil then
		local match_opcode = check["opcode"]
		local targetRace = IEex_ReadByte(currentShare + 0x26, 0x0)
		local targetSubrace = IEex_ReadByte(currentShare + 0x7FF, 0x0)
		local hasProtection = false
		if (match_opcode == 39 and (targetRace == 2 or targetRace == 3 or targetRace == 183)) or ((match_opcode == 109 or match_opcode == 175) and ((targetRace == 4 and targetSubrace == 2) or targetRace == 185)) then
			hasProtection = true
		elseif ((match_opcode == 55 or match_opcode == 420) and IEex_GetActorSpellState(checkID, 8)) or ((match_opcode == 40 or match_opcode == 109 or match_opcode == 154 or match_opcode == 157 or match_opcode == 158 or match_opcode == 175 or match_opcode == 176) and IEex_GetActorSpellState(checkID, 29)) then
			hasProtection = true
		elseif ((match_opcode == 24 or match_opcode == 236) and IEex_GetActorStat(checkID, 102) >= 2) or (match_opcode == 25 and (IEex_GetActorStat(checkID, 99) >= 9 or IEex_GetActorStat(checkID, 101) >= 11)) or (match_opcode == 78 and (IEex_GetActorStat(checkID, 101) >= 5 or IEex_GetActorStat(checkID, 102) >= 1)) then
			hasProtection = true
		else
			IEex_IterateActorEffects(checkID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				if (theopcode == 101 or theopcode == 261) and theparameter2 == match_opcode then
					hasProtection = true
				end
			end)
		end
		if hasProtection then return false end
	end
	if check["spell"] ~= nil then
		local protectionRES = check["spell"]
		local hasProtection = false
		IEex_IterateActorEffects(checkID, function(eData)
			local theopcode = IEex_ReadDword(eData + 0x10)
			local theresource = IEex_ReadLString(eData + 0x30, 8)
			if (theopcode == 206 or theopcode == 290) and theresource == protectionRES then
				hasProtection = true
			end
		end)
		if hasProtection then return false end
	end
	return true
end

function IEex_CheckHeightBelow(heightCompare)
	local sourceID = IEex_Lua_ActorID
	local creatureData = IEex_GetActorShare(sourceID)
	local height = IEex_ReadSignedWord(creatureData + 0x720, 0x0)
	if height < heightCompare then
		return true
	else
		return false
	end
end

function IEex_IsOutdoors()
	local sourceID = IEex_Lua_ActorID
	local creatureData = IEex_GetActorShare(sourceID)
	local areaData = IEex_ReadDword(creatureData + 0x12)
	if areaData > 0 then
		local areaType = IEex_ReadWord(areaData + 0x40, 0x0)
		if bit.band(areaType, 0x1) > 0 then
			return true
		end
	end
	return false
end

function IEex_HasDroppableItems(BCSObject)
	local checkID = IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)
	if not IEex_IsSprite(checkID, false) then return false end
	local checkData = IEex_GetActorShare(checkID)
	local hasDroppableItems = false
	for i = 0, 50, 1 do
		local slotData = IEex_ReadDword(checkData + 0x4AD8 + i * 0x4)
		if slotData > 0 then
			local itemRES = IEex_ReadLString(slotData + 0xC, 8)
			local resWrapper = IEex_DemandRes(itemRES, "ITM")
			if resWrapper:isValid() then
				local itemData = resWrapper:getData()
				local itemFlags = IEex_ReadDword(itemData + 0x18)
				if bit.band(itemFlags, 0x4) > 0 then
					hasDroppableItems = true
				end
			end
			resWrapper:free()
		end
	end
	return hasDroppableItems
end

function IEex_TransferInventoryAR5202(BCSObject)
	local checkID = IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)
	if not IEex_IsSprite(checkID, false) then return false end
	local checkData = IEex_GetActorShare(checkID)
	local itemTransferCount = 0
	for i = 0, 50, 1 do
		local slotData = IEex_ReadDword(checkData + 0x4AD8 + i * 0x4)
		if slotData > 0 then
			local itemRES = IEex_ReadLString(slotData + 0xC, 8)
			local resWrapper = IEex_DemandRes(itemRES, "ITM")
			if resWrapper:isValid() then
				local itemData = resWrapper:getData()
				local itemFlags = IEex_ReadDword(itemData + 0x18)
				if bit.band(itemFlags, 0x4) > 0 then
					if itemTransferCount <= 24 then
						IEex_Eval('GiveItem(\"' .. itemRES .. '\", \"USMOROT1\")',checkID)
					else
						IEex_Eval('GiveItem(\"' .. itemRES .. '\", \"USMOROT2\")',checkID)
					end
				end
			end
			resWrapper:free()
		end
	end
end

function IEex_CheckInventoryItems(BCSObject)
	local checkID = IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)
	if not IEex_IsSprite(checkID, false) then return false end
	local checkData = IEex_GetActorShare(checkID)
	for i = 0, 50, 1 do
		local slotData = IEex_ReadDword(checkData + 0x4AD8 + i * 0x4)
		if slotData > 0 then
			local itemRES = IEex_ReadLString(slotData + 0xC, 8)
			local slotFlags = IEex_ReadDword(slotData + 0x20)
			local resWrapper = IEex_DemandRes(itemRES, "ITM")
			if resWrapper:isValid() then
				local itemData = resWrapper:getData()
				local nameRef = IEex_ReadDword(itemData + 0x8)
				local itemFlags = IEex_ReadDword(itemData + 0x18)
				if IEex_ReadDword(itemData + 0xC) > 0 and (bit.band(slotFlags, 0x1) > 0) then
					nameRef = IEex_ReadDword(itemData + 0xC)
				end
				IEex_SetToken("EXINVSLOT" .. i, IEex_FetchString(nameRef))
			end
			resWrapper:free()
		end
	end
end

ex_non_rechargable_items = {["52BOOKAD"] = true, ["52HFBKAD"] = true, }

function IEex_HasChargeItemInSlot(BCSObject, slot)
	local checkID = IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)
	if not IEex_IsSprite(checkID, false) then return false end
	local checkData = IEex_GetActorShare(checkID)
	local hasChargeItem = false
	local slotData = IEex_ReadDword(checkData + 0x4AD8 + slot * 0x4)
	if slotData > 0 then
		local itemRES = IEex_ReadLString(slotData + 0xC, 8)
		if ex_non_rechargable_items[itemRES] then return false end
		local slotFlags = IEex_ReadDword(slotData + 0x20)
		local resWrapper = IEex_DemandRes(itemRES, "ITM")
		if resWrapper:isValid() then
			local itemData = resWrapper:getData()
			local itemFlags = IEex_ReadDword(itemData + 0x18)
			local maximumInStack = IEex_ReadWord(itemData + 0x38, 0x0)
			if maximumInStack <= 1 and bit.band(itemFlags, 0x40) > 0 then
				local headerOffset = IEex_ReadDword(itemData + 0x64)
				local numHeaders = IEex_ReadWord(itemData + 0x68, 0x0)
				for header = 0, numHeaders, 1 do
					local headerType = IEex_ReadByte(itemData + headerOffset + header * 0x38, 0x0)
					local maxCharges = IEex_ReadWord(itemData + headerOffset + header * 0x38 + 0x22, 0x0)
					local whenDrained = IEex_ReadWord(itemData + headerOffset + header * 0x38 + 0x24, 0x0)
					if headerType == 3 and maxCharges > 0 and (maxCharges > 1 or whenDrained ~= 1) and IEex_ReadWord(slotData + 0x18 + header * 0x2, 0x0) < maxCharges then
						hasChargeItem = true
					end
				end
			end
		end
		resWrapper:free()
	end
	return hasChargeItem
end

function IEex_RechargeItemInSlot(BCSObject, slot, rechargeAmount)
	local checkID = IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)
	if not IEex_IsSprite(checkID, false) then return false end
	local checkData = IEex_GetActorShare(checkID)
	local hasChargeItem = false
	local slotData = IEex_ReadDword(checkData + 0x4AD8 + slot * 0x4)
	if slotData > 0 then
		local itemRES = IEex_ReadLString(slotData + 0xC, 8)
		if ex_non_rechargable_items[itemRES] then return false end
		local slotFlags = IEex_ReadDword(slotData + 0x20)
		local resWrapper = IEex_DemandRes(itemRES, "ITM")
		if resWrapper:isValid() then
			local itemData = resWrapper:getData()
			local itemFlags = IEex_ReadDword(itemData + 0x18)
			local maximumInStack = IEex_ReadWord(itemData + 0x38, 0x0)
			if maximumInStack <= 1 and bit.band(itemFlags, 0x40) > 0 then
				local headerOffset = IEex_ReadDword(itemData + 0x64)
				local numHeaders = IEex_ReadWord(itemData + 0x68, 0x0)
				for header = 0, numHeaders, 1 do
					local headerType = IEex_ReadByte(itemData + headerOffset + header * 0x38, 0x0)
					local maxCharges = IEex_ReadWord(itemData + headerOffset + header * 0x38 + 0x22, 0x0)
					local whenDrained = IEex_ReadWord(itemData + headerOffset + header * 0x38 + 0x24, 0x0)
					if headerType == 3 and maxCharges > 0 and (maxCharges > 1 or whenDrained ~= 1) then
						local currentCharges = IEex_ReadWord(slotData + 0x18 + header * 0x2, 0x0)
						currentCharges = currentCharges + rechargeAmount
						if currentCharges > maxCharges then
							currentCharges = maxCharges
						end
						IEex_WriteWord(slotData + 0x18 + header * 0x2, currentCharges)
						if slot >= 15 and slot <= 17 then
							for quickItemOffset = 0x3828, 0x38A0, 0x3C do
								if IEex_ReadByte(checkData + quickItemOffset + 0x1C, 0x0) == slot and IEex_ReadByte(checkData + quickItemOffset + 0x1E, 0x0) == header then
									IEex_WriteWord(checkData + quickItemOffset + 0x18, currentCharges)
									if currentCharges > 0 then
										IEex_WriteByte(checkData + quickItemOffset + 0x3A, 0)
									end
								end
							end
						end
					end
				end
			end
		end
		resWrapper:free()
	end
end

function IEex_ReleaseSoulFromInventory(BCSObject)
	local checkID = IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)
	if not IEex_IsSprite(checkID, false) then return false end
	local checkData = IEex_GetActorShare(checkID)
	local soulID = nil
	IEex_IterateActorEffects(checkID, function(eData)
		local theopcode = IEex_ReadDword(eData + 0x10)
		local thesavingthrow = IEex_ReadDword(eData + 0x40)
		local theparent_resource = IEex_ReadLString(eData + 0x94, 8)
		if theopcode == 0 and theparent_resource == "USSOULID" then
			local soulConstantID = IEex_ReadDword(eData + 0x60)
			soulID = IEex_Helper_GetBridge("IEex_ConstantID", soulConstantID)
		end
	end)
	if soulID ~= nil and IEex_IsSprite(soulID, true) then
		local soulData = IEex_GetActorShare(soulID)
		local extraFlags = IEex_ReadDword(soulData + 0x740)
		IEex_WriteDword(soulData + 0x740, bit.band(extraFlags, 0xCFFFFFFF))
	end
end

function IEex_ReplaceItemInSlot(BCSObject, slot, itemRES, charges1, charges2, charges3, flagsToSet, flagsToUnset)
	local checkID = IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)
	if not IEex_IsSprite(checkID, true) then return false end
	local checkData = IEex_GetActorShare(checkID)
	local slotData = IEex_ReadDword(checkData + 0x4AD8 + slot * 0x4)
	if slotData > 0 then
		if itemRES ~= "DEFAULT" then
			IEex_WriteLString(slotData + 0xC, itemRES, 8)
		end
		if charges1 and charges1 ~= -1 then
			IEex_WriteWord(slotData + 0x18, charges1)
		end
		if charges2 and charges2 ~= -1 then
			IEex_WriteWord(slotData + 0x1A, charges1)
		end
		if charges3 and charges3 ~= -1 then
			IEex_WriteWord(slotData + 0x1C, charges1)
		end
		local flags = IEex_ReadDword(slotData + 0x20)
		if flagsToSet then
			flags = bit.bor(flags, flagsToSet)
		end
		if flagsToUnset then
			flags = bit.band(flags, (0xFFFFFFFF - flagsToUnset))
		end
		IEex_WriteDword(slotData + 0x20, flags)
	end
end

function IEex_HasMeleeWeaponEquipped(BCSObject)
	local checkID = IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)
	if not IEex_IsSprite(checkID, false) then return false end
	local checkData = IEex_GetActorShare(checkID)
	local hasMeleeWeaponEquipped = false
	local weaponSlot = IEex_ReadByte(checkData + 0x4BA4, 0x0)
	local weaponHeader = IEex_ReadByte(checkData + 0x4BA6, 0x0)
	local slotData = IEex_ReadDword(checkData + 0x4AD8 + weaponSlot * 0x4)
	if slotData > 0 then
		local weaponRES = IEex_ReadLString(slotData + 0xC, 8)
		local resWrapper = IEex_DemandRes(weaponRES, "ITM")
		if resWrapper:isValid() then
			local itemData = resWrapper:getData()
			local numHeaders = IEex_ReadSignedWord(itemData + 0x68, 0x0)
			if weaponHeader >= numHeaders then
				weaponHeader = 0
			end
			local itemType = IEex_ReadWord(itemData + 0x1C, 0x0)
			local headerType = IEex_ReadByte(itemData + 0x82 + weaponHeader * 0x38, 0x0)
			if headerType == 1 then
				hasMeleeWeaponEquipped = true
			end
		end
		resWrapper:free()
	end
	return hasMeleeWeaponEquipped
end

function IEex_IsImmuneToOpcode(BCSObject, match_opcode)
	local sourceID = IEex_Lua_ActorID
	local sourceData = IEex_GetActorShare(sourceID)
	local checkID = IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)
	if not IEex_IsSprite(checkID, false) then return false end
	local checkData = IEex_GetActorShare(checkID)
	local hasProtection = false
	if protectionType == 0 then
		local targetRace = IEex_ReadByte(checkData + 0x26, 0x0)
		local targetSubrace = IEex_ReadByte(checkData + 0x7FF, 0x0)
		if (match_opcode == 39 and (targetRace == 2 or targetRace == 3 or targetRace == 183)) or ((match_opcode == 109 or match_opcode == 175) and ((targetRace == 4 and targetSubrace == 2) or targetRace == 185)) then
			hasProtection = true
		elseif ((match_opcode == 55 or match_opcode == 420) and IEex_GetActorSpellState(checkID, 8)) or ((match_opcode == 40 or match_opcode == 109 or match_opcode == 154 or match_opcode == 157 or match_opcode == 158 or match_opcode == 175 or match_opcode == 176) and IEex_GetActorSpellState(checkID, 29)) then
			hasProtection = true
		elseif ((match_opcode == 24 or match_opcode == 236) and IEex_GetActorStat(checkID, 102) >= 2) or (match_opcode == 25 and (IEex_GetActorStat(checkID, 99) >= 9 or IEex_GetActorStat(checkID, 101) >= 11)) or (match_opcode == 78 and (IEex_GetActorStat(checkID, 101) >= 5 or IEex_GetActorStat(checkID, 102) >= 1)) then
			hasProtection = true
		elseif (match_opcode == 5 or match_opcode == 412) and IEex_GetActorSpellState(checkID, 1) and sourceData > 0 and bit.band(IEex_ReadByte(sourceData + 0x35, 0x0), 0x3) == 0x3 then
			hasProtection = true
		else
			IEex_IterateActorEffects(checkID, function(eData)
				local theopcode = IEex_ReadDword(eData + 0x10)
				local theparameter2 = IEex_ReadDword(eData + 0x20)
				if (theopcode == 101 or theopcode == 261) and theparameter2 == match_opcode then
					hasProtection = true
				end
			end)
		end
	end
	return hasProtection
end

function IEex_KnowsSpell(BCSObject, spellNumber)
	local sourceID = IEex_Lua_ActorID
	local sourceData = IEex_GetActorShare(sourceID)
	local checkID = IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)
	if not IEex_IsSprite(checkID, false) then return false end
	local spellRES = ""
	local spellPrefixNumber = math.floor(spellNumber / 1000)
	local spellSuffix = tostring(spellNumber % 1000)
	if #spellSuffix == 1 then
		spellSuffix = "00" .. spellSuffix
	elseif #spellSuffix == 2 then
		spellSuffix = "0" .. spellSuffix
	end
	if spellPrefixNumber == 1 then
		spellRES = "SPPR" .. spellSuffix
	elseif spellPrefixNumber == 2 then
		spellRES = "SPWI" .. spellSuffix
	elseif spellPrefixNumber == 5 then
		spellRES = "USPR" .. spellSuffix
	elseif spellPrefixNumber == 6 then
		spellRES = "USWI" .. spellSuffix
	elseif spellPrefixNumber == 10 then
		spellRES = "USES" .. spellSuffix
	end
	local knowsSpell = false
	local spells = IEex_FetchSpellInfo(checkID, {1, 2, 3, 4, 5, 6, 7, 8})
	for i = 1, 9, 1 do
		for cType, levelList in pairs(spells) do
			if #levelList >= i then
				local levelI = levelList[i]
				local maxCastable = levelI[1]
				local sorcererCastableCount = levelI[2]
				local levelISpells = levelI[3]
				if #levelISpells > 0 then
					for i2, spell in ipairs(levelISpells) do
						if spellRES == spell["resref"] then
							knowsSpell = true
						end
					end
				end
			end
		end
	end
	local abilities = IEex_FetchSpellInfo(checkID, {9})
	local levelList = abilities[9]
	local levelISpells = levelList[1]
	for i2, spell in ipairs(levelISpells) do
		if spellRES == spell["resref"] then
			knowsSpell = true
		end
	end
	return knowsSpell
end

function IEex_CheckSearchMapColor(colorList)
	local sourceID = IEex_Lua_ActorID
	local creatureData = IEex_GetActorShare(sourceID)
	local targetX = IEex_ReadDword(creatureData + 0x6)
	local targetY = IEex_ReadDword(creatureData + 0xA)
	local areaData = IEex_ReadDword(creatureData + 0x12)
	local areaRES = ""
--	local areaX = 32767
--	local areaY = 32767
	if areaData > 0 then
		areaRES = IEex_ReadLString(areaData, 8)
--		areaX = IEex_ReadDword(areaData + 0x54C)
--		areaY = IEex_ReadDword(areaData + 0x550)
	end
	local searchMapWrapper = IEex_DemandRes(areaRES .. "SR", "BMP")
	local currentZone = -1
	if searchMapWrapper:isValid() then
		local searchMapData = searchMapWrapper:getData()
		currentZone = IEex_GetBitmapPixelIndex(searchMapData, math.floor(targetX / 16), math.floor(targetY / 12))
	end
	searchMapWrapper:free()
	if type(colorList) == "number" then
		if colorList == currentZone then
			return true
		else
			return false
		end
	else
		for k, v in ipairs(colorList) do
			if type(v) == "boolean" then
				if v == true and k == currentZone then
					return true
				end
			else
				if v == currentZone then
					return true
				end
			end
		end
		return false
	end
end

function IEex_IsPartyAIOn()
	local gameData = IEex_GetGameData()
	return (bit.band(IEex_ReadByte(gameData + 0x4A8E, 0x0), 0x1) > 0)
end

function IEex_IsPartyMemberInitialized(characterNum)
	local actorID = IEex_GetActorIDCharacter(characterNum)
	local creatureData = IEex_GetActorShare(actorID)
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	return (bit.band(extraFlags, 0x2) > 0)
end

function IEex_InitializePartyMember(characterNum)
	local actorID = IEex_GetActorIDCharacter(characterNum)
	local creatureData = IEex_GetActorShare(actorID)
	local extraFlags = IEex_ReadDword(creatureData + 0x740)
	extraFlags = bit.bor(extraFlags, 0x2)
	IEex_WriteDword(creatureData + 0x740, extraFlags)
end
USWSHSTR = "USWSHSTR"
USWSHDEX = "USWSHDEX"
USWSHCON = "USWSHCON"
USWSHINT = "USWSHINT"
USWSHWIS = "USWSHWIS"
USWSHCHR = "USWSHCHR"
USWSHRST = "USWSHRST"
function IEex_HaveSummonerCast(spellNumber, isInstant)
	local summonerID = IEex_GetActorSummonerID(IEex_Lua_ActorID)
	if not IEex_IsSprite(summonerID, false) then return end
	local creatureData = IEex_GetActorShare(summonerID)
	local sorcererLevel = IEex_GetActorStat(summonerID, 105)
	local wizardLevel = IEex_GetActorStat(summonerID, 106)
	local casterLevel = wizardLevel
	local casterlvl = wizardLevel + 0xB00
	if sorcererLevel > wizardLevel then
		casterLevel = sorcererLevel
		casterlvl = sorcererLevel + 0xA00
	end
	if wizardLevel <= 0 and sorcererLevel <= 0 then
		casterLevel = IEex_GetActorStat(summonerID, 95)
		casterlvl = casterLevel
	end
	local spellRES = ""
	if type(spellNumber) == "string" then
		spellRES = spellNumber
	elseif type(spellNumber) == "number" then
		local spellPrefixNumber = math.floor(spellNumber / 1000)
		local spellSuffix = tostring(spellNumber % 1000)
		if #spellSuffix == 1 then
			spellSuffix = "00" .. spellSuffix
		elseif #spellSuffix == 2 then
			spellSuffix = "0" .. spellSuffix
		end
		if spellPrefixNumber == 1 then
			spellRES = "SPPR" .. spellSuffix
		elseif spellPrefixNumber == 2 then
			spellRES = "SPWI" .. spellSuffix
		elseif spellPrefixNumber == 5 then
			spellRES = "USPR" .. spellSuffix
		elseif spellPrefixNumber == 6 then
			spellRES = "USWI" .. spellSuffix
		elseif spellPrefixNumber == 10 then
			spellRES = "USES" .. spellSuffix
		end
	end
	if not isInstant then
		IEex_ApplyEffectToActor(summonerID, {
["opcode"] = 146,
["target"] = 2,
["timing"] = 1,
["parameter1"] = casterLevel,
["parameter2"] = 1,
["savingthrow"] = 0x10000,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["source_x"] = IEex_ReadDword(creatureData + 0x6),
["source_y"] = IEex_ReadDword(creatureData + 0xA),
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterlvl,
["source_id"] = summonerID
})
	else
		IEex_ApplyEffectToActor(summonerID, {
["opcode"] = 402,
["target"] = 2,
["timing"] = 1,
["resource"] = spellRES,
["parent_resource"] = spellRES,
["source_x"] = IEex_ReadDword(creatureData + 0x6),
["source_y"] = IEex_ReadDword(creatureData + 0xA),
["target_x"] = IEex_ReadDword(creatureData + 0x6),
["target_y"] = IEex_ReadDword(creatureData + 0xA),
["casterlvl"] = casterlvl,
["source_id"] = summonerID
})
	end
end

function IEex_RemoveMemorizedSpellRES(spellRES, BCSObject, casterType)
	local sourceID = IEex_Lua_ActorID
	local sourceData = IEex_GetActorShare(sourceID)
	local checkID = IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)
	if not IEex_IsSprite(checkID, false) then return false end
	local modifyRemaining = 1
	local maxLevel = 9
	local minLevel = 0
	local casterTypes = {}
	if casterType then
		casterTypes = {casterType}
	else
		casterTypes = {1, 2, 3, 4, 5, 6, 7, 8}
	end
	local spells = IEex_FetchSpellInfo(checkID, casterTypes)
	for i = maxLevel, minLevel, -1 do
		for cType, levelList in pairs(spells) do
			if #levelList >= i then
				local levelI = levelList[i]
				if levelI then
					local maxCastable = levelI[1]
					local sorcererCastableCount = levelI[2]
					local levelISpells = levelI[3]
					if #levelISpells > 0 then
						if cType == 1 or cType == 6 then
							local matchSpellFound = true
							matchSpellFound = false
							for i2, spell in ipairs(levelISpells) do
								if spellRES == spell["resref"] then
									matchSpellFound = true
								end
							end
							if matchSpellFound then
								if modifyRemaining > 0 then
									modifyRemaining = modifyRemaining - 1
									IEex_AlterSpellInfo(checkID, cType, i, "", 0, -1)
								end
							end
						else
							for i2, spell in ipairs(levelISpells) do
								if spellRES == spell["resref"] then
									if modifyRemaining > 0 then
										modifyRemaining = modifyRemaining - 1
										IEex_AlterSpellInfo(checkID, cType, i, spell["resref"], 0, -1)
									end
								end
							end
						end
					end
				end
			end
		end
	end
end

function IEex_CheckCanSee()
	local sourceID = IEex_Lua_ActorID
	local creatureData = IEex_GetActorShare(sourceID)
	local targetID = IEex_ReadDword(creatureData + 0x34C)
	if not IEex_IsSprite(targetID, false) then return false end
	local targetShare = IEex_GetActorShare(targetID)
	local sourceHeight = IEex_ReadSignedWord(creatureData + 0x720, 0x0)
	local targetHeight = IEex_ReadSignedWord(targetShare + 0x720, 0x0)
	if targetHeight < 0 and IEex_GetSpellState(targetID, 218) and not IEex_GetSpellState(sourceID, 218) then return false end
	return true
end

function IEex_IsDisarmed()
	local sourceID = IEex_Lua_ActorID
	local objectData = IEex_GetActorShare(sourceID)
	local objectType = IEex_ReadByte(objectData + 0x4, 0x0)
	if objectType == 0x11 then
		return (IEex_ReadByte(objectData + 0x896, 0x0) == 0)
	elseif objectType == 0x21 then
		return (IEex_ReadByte(objectData + 0x64C, 0x0) == 0)
	elseif objectType == 0x41 then
		return (IEex_ReadByte(objectData + 0x612, 0x0) == 0)
	else
		return false
	end
end

function IEex_WasJustDisarmed()
	local sourceID = IEex_Lua_ActorID
	local objectData = IEex_GetActorShare(sourceID)
	local objectType = IEex_ReadByte(objectData + 0x4, 0x0)
	if objectType == 0x11 then
		local flags = IEex_ReadDword(objectData + 0x88E)
		if IEex_ReadByte(objectData + 0x896, 0x0) == 0 and bit.band(flags, 0x2000000) > 0 then
			IEex_WriteDword(objectData + 0x88E, bit.band(flags, 0xFDFFFFFF))
			return true
		else
			return false
		end
	elseif objectType == 0x21 then
		local flags = IEex_ReadDword(objectData + 0x5C4)
		if IEex_ReadByte(objectData + 0x64C, 0x0) == 0 and bit.band(flags, 0x2000000) > 0 then
			IEex_WriteDword(objectData + 0x5C4, bit.band(flags, 0xFDFFFFFF))
			return true
		else
			return false
		end
	elseif objectType == 0x41 then
		local flags = IEex_ReadDword(objectData + 0x5D6)
		if IEex_ReadByte(objectData + 0x612, 0x0) == 0 and bit.band(flags, 0x2000000) > 0 then
			IEex_WriteDword(objectData + 0x5D6, bit.band(flags, 0xFDFFFFFF))
			return true
		else
			return false
		end
	else
		return false
	end
end

function IEex_IsUnlocked()
	local sourceID = IEex_Lua_ActorID
	local objectData = IEex_GetActorShare(sourceID)
	local objectType = IEex_ReadByte(objectData + 0x4, 0x0)
	if objectType == 0x11 then
		local flags = IEex_ReadDword(objectData + 0x88E)
		return (bit.band(flags, 0x1) == 0)
	elseif objectType == 0x21 then
		local flags = IEex_ReadDword(objectData + 0x5C4)
		return (bit.band(flags, 0x2) == 0)
	else
		return false
	end
end

function IEex_WasJustUnlocked()
	local sourceID = IEex_Lua_ActorID
	local objectData = IEex_GetActorShare(sourceID)
	local objectType = IEex_ReadByte(objectData + 0x4, 0x0)
	if objectType == 0x11 then
		local flags = IEex_ReadDword(objectData + 0x88E)
		if bit.band(flags, 0x1) == 0 and bit.band(flags, 0x1000000) > 0 then
			IEex_WriteDword(objectData + 0x88E, bit.band(flags, 0xFEFFFFFF))
			return true
		else
			return false
		end
	elseif objectType == 0x21 then
		local flags = IEex_ReadDword(objectData + 0x5C4)
		if bit.band(flags, 0x2) == 0 and bit.band(flags, 0x1000000) > 0 then
			IEex_WriteDword(objectData + 0x5C4, bit.band(flags, 0xFEFFFFFF))
			return true
		else
			return false
		end
	else
		return false
	end
end

function IEex_SetKillCountToken(BCSObject)
	local checkID = IEex_GetBCSObjectID(IEex_Lua_ActorID, BCSObject)
	local checkData = IEex_GetActorShare(checkID)
	if checkData == 0 then return end
	IEex_SetToken("EXKILLCOUNT", IEex_ReadDword(checkData + 0x4BD6))
end

function IEex_SetBanter()
	local validPartyDLGS = {}
	local areaCheck = -1
	for i = 0, 5, 1 do
		local share = IEex_GetActorShare(IEex_GetActorIDCharacter(i))
		if share > 0 then
			local stateValue = bit.bor(IEex_ReadDword(share + 0x5BC), IEex_ReadDword(share + 0x920))
			local currentArea = IEex_ReadDword(share + 0x12)
			if areaCheck == -1 then
				areaCheck = currentArea
			elseif areaCheck ~= currentArea then
				return
			end
			if bit.band(stateValue, 0x80103FFF) == 0 then
				validPartyDLGS[IEex_ReadLString(share + 0x56DC, 8)] = true
			end
		end
	end
	for k, v in ipairs(ex_timed_banter_list) do
		local doBanter = true
		if v["dlgs"] ~= nil and v["dlgs"][1] ~= nil and v["id"] ~= nil and v["globals"] ~= nil then
			local initiatingDLG = v["dlgs"][1]
			local id = v["id"]
			for k2, v2 in ipairs(v["dlgs"]) do
				if not validPartyDLGS[v2] then
					doBanter = false
				end
			end
			if doBanter then
				for k2, v2 in ipairs(v["globals"]) do
					local theglobal = IEex_GetGlobal(v2[1])
					local theop = v2[2]
					local theval = v2[3]
					if (theop == "=" or theop == "==") and theglobal ~= theval then
						doBanter = false
					elseif (theop == "!=" or theop == "~=") and theglobal == theval then
						doBanter = false
					elseif (theop == ">") and theglobal <= theval then
						doBanter = false
					elseif (theop == "<") and theglobal >= theval then
						doBanter = false
					elseif (theop == "<=") and theglobal > theval then
						doBanter = false
					elseif (theop == ">=") and theglobal < theval then
						doBanter = false
					end
				end
			end
			if doBanter and IEex_GetGlobal("DIDBANTER" .. initiatingDLG .. "_" .. id) == 1 then
				doBanter = false
			end
			if doBanter then
				IEex_SetGlobal("BANTER" .. initiatingDLG, id)
			end
		end
	end
end

USREIG = "USREIG"
USGEOF = "USGEOF"
USVEIR = "USVEIR"
USEMMA = "USEMMA"
USVREK = "USVREK"
USVUNA = "USVUNA"
USZACK = "USZACK"
USXHAA = "USXHAA"
USPAIR = "USPAIR"
USSERS = "USSERS"

function IEex_IfValidForPartyDialogue(scriptName)
	local sourceID = IEex_Lua_ActorID
	local sourceData = IEex_GetActorShare(sourceID)
	if not scriptName then
		scriptName = IEex_ReadLString(sourceData + 0x554, 32)
	end
	local canBanter = false
	for i = 0, 5, 1 do
		local share = IEex_GetActorShare(IEex_GetActorIDCharacter(i))
		if share > 0 then
		end
		if share > 0 and IEex_ReadLString(share + 0x554, 32) == scriptName then
			local stateValue = bit.bor(IEex_ReadDword(share + 0x5BC), IEex_ReadDword(share + 0x920))
			if bit.band(stateValue, 0x80103FFF) == 0 and IEex_ReadDword(sourceData + 0x12) == IEex_ReadDword(share + 0x12) and IEex_ReadDword(IEex_GetActorShare(IEex_GetActorIDCharacter(0)) + 0x12) == IEex_ReadDword(share + 0x12) then
				canBanter = true
			end
		end
	end
	return canBanter
end

function IEex_AllPartyMembersCanBanter()
	local areaCheck = -1
	for i = 0, 5, 1 do
		local share = IEex_GetActorShare(IEex_GetActorIDCharacter(i))
		if share > 0 then
			local stateValue = bit.bor(IEex_ReadDword(share + 0x5BC), IEex_ReadDword(share + 0x920))
			local currentArea = IEex_ReadDword(share + 0x12)
			if areaCheck == -1 then
				areaCheck = currentArea
			elseif areaCheck ~= currentArea then
				return false
			end
			if bit.band(stateValue, 0x80103FFF) ~= 0 then
				return false
			end
		end
	end
	return true
end

function IEex_StealthTimerExpired()
	local sourceID = IEex_Lua_ActorID
	local objectData = IEex_GetActorShare(sourceID)
	if objectData <= 0 then return false end
	local objectType = IEex_ReadByte(objectData + 0x4, 0x0)
	if objectType ~= 0x31 then return false end
	local stealthTimer = IEex_ReadSignedByte(objectData + 0x727A, 0x0)
	return (stealthTimer == 0 or stealthTimer == -1)
end