diff --git a/config.lua b/config.lua
index 5bedf78..e354f60 100644
--- a/config.lua
+++ b/config.lua
@@ -69,7 +69,9 @@ freePremium = false
 kickIdlePlayerAfterMinutes = 15
 maxMessageBuffer = 4
 showMonsterLoot = false
-queryPlayerContainers = false
+blockHeight = false
+dropItems = false
+
 
 -- Character Rooking
 -- Level threshold is the level requirement to teleport players back to newbie town
diff --git a/data/actions/scripts/misc/fluids.lua b/data/actions/scripts/misc/fluids.lua
index 3277f38..e300dcb 100644
--- a/data/actions/scripts/misc/fluids.lua
+++ b/data/actions/scripts/misc/fluids.lua
@@ -2,7 +2,12 @@ local drunk = Condition(CONDITION_DRUNK)
 drunk:setParameter(CONDITION_PARAM_TICKS, 60000)
 
 local poison = Condition(CONDITION_POISON)
-poison:setTiming(100)
+poison:setParameter(CONDITION_PARAM_DELAYED, true)
+poison:setParameter(CONDITION_PARAM_MINVALUE, -50)
+poison:setParameter(CONDITION_PARAM_MAXVALUE, -120)
+poison:setParameter(CONDITION_PARAM_STARTVALUE, -5)
+poison:setParameter(CONDITION_PARAM_TICKINTERVAL, 5000)
+poison:setParameter(CONDITION_PARAM_FORCEUPDATE, true)
 
 local messages = {
 	[FLUID_WATER] = "Gulp.",
diff --git a/data/creaturescripts/scripts/firstitems.lua b/data/creaturescripts/scripts/firstitems.lua
index 7c837c9..0c3c75a 100644
--- a/data/creaturescripts/scripts/firstitems.lua
+++ b/data/creaturescripts/scripts/firstitems.lua
@@ -1,7 +1,5 @@
 function onLogin(player)
-	if player:getLastLoginSaved() <= 0 or player:getStorageValue(30017) == 1 then
-		player:setStorageValue(30017, 0) -- reset storage for first items
-		
+	if player:getLastLoginSaved() <= 0 then
 		-- Items
 		if player:getSex() == PLAYERSEX_FEMALE then
 			player:addItem(3562, 1, true, -1, CONST_SLOT_ARMOR)
diff --git a/data/events/events.xml b/data/events/events.xml
new file mode 100644
index 0000000..1b75858
--- /dev/null
+++ b/data/events/events.xml
@@ -0,0 +1,28 @@
+
+
+	
+	
+	
+	
+
+	
+	
+	
+	
+	
+
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+
diff --git a/data/events/scripts/creature.lua b/data/events/scripts/creature.lua
new file mode 100644
index 0000000..ac4ff89
--- /dev/null
+++ b/data/events/scripts/creature.lua
@@ -0,0 +1,11 @@
+function Creature:onChangeOutfit(outfit)
+	return true
+end
+
+function Creature:onAreaCombat(tile, isAggressive)
+	return RETURNVALUE_NOERROR
+end
+
+function Creature:onTargetCombat(target)
+	return RETURNVALUE_NOERROR
+end
diff --git a/data/events/scripts/party.lua b/data/events/scripts/party.lua
new file mode 100644
index 0000000..1a6b561
--- /dev/null
+++ b/data/events/scripts/party.lua
@@ -0,0 +1,35 @@
+function Party:onJoin(player)
+	return true
+end
+
+function Party:onLeave(player)
+	return true
+end
+
+function Party:onDisband()
+	return true
+end
+
+function Party:onShareExperience(exp)
+	local sharedExperienceMultiplier = 1.20 --20%
+	local vocationsIds = {}
+
+	local vocationId = self:getLeader():getVocation():getBase():getId()
+	if vocationId ~= VOCATION_NONE then
+		table.insert(vocationsIds, vocationId)
+	end
+
+	for _, member in ipairs(self:getMembers()) do
+		vocationId = member:getVocation():getBase():getId()
+		if not table.contains(vocationsIds, vocationId) and vocationId ~= VOCATION_NONE then
+			table.insert(vocationsIds, vocationId)
+		end
+	end
+
+	local size = #vocationsIds
+	if size > 1 then
+		sharedExperienceMultiplier = 1.0 + ((size * (5 * (size - 1) + 10)) / 100)
+	end
+
+	return (exp * sharedExperienceMultiplier) / (#self:getMembers() + 1)
+end
diff --git a/data/events/scripts/player.lua b/data/events/scripts/player.lua
new file mode 100644
index 0000000..86262d7
--- /dev/null
+++ b/data/events/scripts/player.lua
@@ -0,0 +1,169 @@
+function Player:onLook(thing, position, distance)
+	local description = "You see " .. thing:getDescription(distance)
+	if self:getGroup():getAccess() then
+		if thing:isItem() then
+			description = string.format("%s\nItem ID: %d", description, thing:getId())
+
+			local actionId = thing:getActionId()
+			if actionId ~= 0 then
+				description = string.format("%s, Action ID: %d", description, actionId)
+			end
+
+			local uniqueId = thing:getAttribute(ITEM_ATTRIBUTE_MOVEMENTID)
+			if uniqueId > 0 and uniqueId < 65536 then
+				description = string.format("%s, Movement ID: %d", description, uniqueId)
+			end
+
+			local itemType = thing:getType()
+
+			local transformEquipId = itemType:getTransformEquipId()
+			local transformDeEquipId = itemType:getTransformDeEquipId()
+			if transformEquipId ~= 0 then
+				description = string.format("%s\nTransforms to: %d (onEquip)", description, transformEquipId)
+			elseif transformDeEquipId ~= 0 then
+				description = string.format("%s\nTransforms to: %d (onDeEquip)", description, transformDeEquipId)
+			end
+
+			local decayId = itemType:getDecayId()
+			if decayId ~= -1 then
+				description = string.format("%s\nDecays to: %d", description, decayId)
+			end
+			if thing:getAttribute(ITEM_ATTRIBUTE_DECAYSTATE) == 1 then
+				description = string.format("%s\nDecaying in %d minutes (%d seconds).", description, thing:getAttribute(ITEM_ATTRIBUTE_DURATION) / 1000 / 60, thing:getAttribute(ITEM_ATTRIBUTE_DURATION) / 1000)
+			end
+		elseif thing:isCreature() then
+			local str = "%s\nHealth: %d / %d"
+			if thing:isPlayer() and thing:getMaxMana() > 0 then
+				str = string.format("%s, Mana: %d / %d", str, thing:getMana(), thing:getMaxMana())
+			end
+			description = string.format(str, description, thing:getHealth(), thing:getMaxHealth()) .. "."
+		end
+
+		local position = thing:getPosition()
+		description = string.format(
+			"%s\nPosition: %d, %d, %d",
+			description, position.x, position.y, position.z
+		)
+
+		if thing:isCreature() then
+			if thing:isPlayer() then
+				description = string.format("%s\nIP: %s.", description, Game.convertIpToString(thing:getIp()))
+			end
+		end
+	end
+	self:sendTextMessage(MESSAGE_INFO_DESCR, description)
+end
+
+function Player:onLookInBattleList(creature, distance)
+	local description = "You see " .. creature:getDescription(distance)
+	if self:getGroup():getAccess() then
+		local str = "%s\nHealth: %d / %d"
+		if creature:isPlayer() and creature:getMaxMana() > 0 then
+			str = string.format("%s, Mana: %d / %d", str, creature:getMana(), creature:getMaxMana())
+		end
+		description = string.format(str, description, creature:getHealth(), creature:getMaxHealth()) .. "."
+
+		local position = creature:getPosition()
+		description = string.format(
+			"%s\nPosition: %d, %d, %d",
+			description, position.x, position.y, position.z
+		)
+
+		if creature:isPlayer() then
+			description = string.format("%s\nIP: %s", description, Game.convertIpToString(creature:getIp()))
+		end
+	end
+	self:sendTextMessage(MESSAGE_INFO_DESCR, description)
+end
+
+function Player:onLookInTrade(partner, item, distance)
+	self:sendTextMessage(MESSAGE_INFO_DESCR, "You see " .. item:getDescription(distance))
+end
+
+function Player:onMoveItem(item, count, fromPosition, toPosition, fromCylinder, toCylinder)
+	return true
+end
+
+function Player:onItemMoved(item, count, fromPosition, toPosition, fromCylinder, toCylinder)
+end
+
+function Player:onMoveCreature(creature, fromPosition, toPosition)
+	return true
+end
+
+function Player:onReportBug(message, position, category)
+	if self:getAccountType() == ACCOUNT_TYPE_NORMAL then
+		return false
+	end
+
+	local name = self:getName()
+	local file = io.open("data/reports/bugs/" .. name .. " report.txt", "a")
+
+	if not file then
+		self:sendTextMessage(MESSAGE_EVENT_DEFAULT, "There was an error when processing your report, please contact a gamemaster.")
+		return true
+	end
+
+	io.output(file)
+	io.write("------------------------------\n")
+	io.write("Name: " .. name)
+	if category == BUG_CATEGORY_MAP then
+		io.write(" [Map position: " .. position.x .. ", " .. position.y .. ", " .. position.z .. "]")
+	end
+	local playerPosition = self:getPosition()
+	io.write(" [Player Position: " .. playerPosition.x .. ", " .. playerPosition.y .. ", " .. playerPosition.z .. "]\n")
+	io.write("Comment: " .. message .. "\n")
+	io.close(file)
+
+	self:sendTextMessage(MESSAGE_EVENT_DEFAULT, "Your report has been sent to " .. configManager.getString(configKeys.SERVER_NAME) .. ".")
+	return true
+end
+
+function Player:onTurn(direction)
+	return true
+end
+
+function Player:onTradeRequest(target, item)
+	return true
+end
+
+function Player:onTradeAccept(target, item, targetItem)
+	return true
+end
+
+local soulCondition = Condition(CONDITION_SOUL, CONDITIONID_DEFAULT)
+soulCondition:setTicks(4 * 60 * 1000)
+soulCondition:setParameter(CONDITION_PARAM_SOULGAIN, 1)
+
+function Player:onGainExperience(source, exp, rawExp)
+	if not source or source:isPlayer() then
+		return exp
+	end
+	
+	-- Soul regeneration
+	local vocation = self:getVocation()
+	if self:getSoul() < vocation:getMaxSoul() and exp >= self:getLevel() then
+		soulCondition:setParameter(CONDITION_PARAM_SOULTICKS, vocation:getSoulGainTicks() * 1000)
+		self:addCondition(soulCondition)
+	end
+
+	-- Apply experience stage multiplier
+	exp = exp * Game.getExperienceStage(self:getLevel())
+
+	return exp
+end
+
+function Player:onLoseExperience(exp)
+	return exp
+end
+
+function Player:onGainSkillTries(skill, tries)
+	if APPLY_SKILL_MULTIPLIER == false then
+		return tries
+	end
+
+	if skill == SKILL_MAGLEVEL then
+		return tries * configManager.getNumber(configKeys.RATE_MAGIC)
+	end
+	return tries * configManager.getNumber(configKeys.RATE_SKILL)
+end
diff --git a/data/global.lua b/data/global.lua
index 89a84ec..13608e1 100644
--- a/data/global.lua
+++ b/data/global.lua
@@ -40,4 +40,8 @@ table.contains = function(array, value)
 		end
 	end
 	return false
+end
+
+function isNumber(str)
+	return tonumber(str) ~= nil
 end
\ No newline at end of file
diff --git a/data/lib/core/core.lua b/data/lib/core/core.lua
index 9491e80..8bc8ac0 100644
--- a/data/lib/core/core.lua
+++ b/data/lib/core/core.lua
@@ -9,3 +9,4 @@ dofile('data/lib/core/player.lua')
 dofile('data/lib/core/position.lua')
 dofile('data/lib/core/teleport.lua')
 dofile('data/lib/core/tile.lua')
+dofile('data/lib/core/vocation.lua')
\ No newline at end of file
diff --git a/data/lib/core/game.lua b/data/lib/core/game.lua
index 5bbec2b..29cacef 100644
--- a/data/lib/core/game.lua
+++ b/data/lib/core/game.lua
@@ -9,7 +9,7 @@ function Game.removeItemsOnMap(position)
 	local i = 0
 	while i < tileCount do
 		local tileItem = tile:getThing(i)
-		if tileItem and not tileItem:isCreature() and ItemType(tileItem:getId()):isMovable() then
+		if tileItem and tileItem:getType():isMovable() then
 			tileItem:remove()
 		else
 			i = i + 1
@@ -24,10 +24,8 @@ function Game.transformItemOnMap(position, itemId, toItemId, subtype)
 
 	local tile = Tile(position)
 	local item = tile:getItemById(itemId)
-	if item ~= nil then
-		item:transform(toItemId, subtype)
-		item:decay()
-	end
+	item:transform(toItemId, subtype)
+	item:decay()
 	return item
 end
 
diff --git a/data/lib/core/tile.lua b/data/lib/core/tile.lua
index c254ad7..de3072f 100644
--- a/data/lib/core/tile.lua
+++ b/data/lib/core/tile.lua
@@ -21,3 +21,45 @@ end
 function Tile.isTile(self)
 	return true
 end
+
+function Tile.relocateTo(self, toPosition, pushMove, monsterPosition)
+	if self:getPosition() == toPosition then
+		return false
+	end
+
+	if not Tile(toPosition) then
+		return false
+	end
+
+	for i = self:getThingCount() - 1, 0, -1 do
+		local thing = self:getThing(i)
+		if thing then
+			if thing:isItem() then
+				if ItemType(thing.itemid):isMovable() then
+					thing:moveTo(toPosition)
+				end
+			elseif thing:isCreature() then
+				if monsterPosition and thing:isMonster() then
+					thing:teleportTo(monsterPosition, pushMove)
+				else
+					thing:teleportTo(toPosition, pushMove)
+				end
+			end
+		end
+	end
+	return true
+end
+
+function Tile:getPlayers()
+	local players = {}
+	local creatures = self:getCreatures()
+	if (creatures) then
+		for i = 1, #creatures do 
+			if (creatures[i]:isPlayer()) then 
+				table.insert(players, creatures[i])
+			end
+		end
+	end
+
+	return players
+end
\ No newline at end of file
diff --git a/data/lib/core/vocation.lua b/data/lib/core/vocation.lua
new file mode 100644
index 0000000..33772a5
--- /dev/null
+++ b/data/lib/core/vocation.lua
@@ -0,0 +1,7 @@
+function Vocation.getBase(self)
+	local base = self
+	while base:getDemotion() do
+		base = base:getDemotion()
+	end
+	return base
+end
\ No newline at end of file
diff --git a/data/movements/scripts/misc/floorchange.lua b/data/movements/scripts/misc/floorchange.lua
index 58b54aa..6e1f365 100644
--- a/data/movements/scripts/misc/floorchange.lua
+++ b/data/movements/scripts/misc/floorchange.lua
@@ -81,8 +81,7 @@ function onStepIn(creature, item, position, fromPosition)
 		return false
 	end
 	
-	doRelocate(position, relPos)
-
+	Tile(item:getPosition()):relocateTo(relPos)
 	if item:getId() == 293 then
 		item:transform(294)
 		item:decay()
diff --git a/data/talkactions/scripts/reload.lua b/data/talkactions/scripts/reload.lua
new file mode 100644
index 0000000..1dd9c14
--- /dev/null
+++ b/data/talkactions/scripts/reload.lua
@@ -0,0 +1,65 @@
+local reloadTypes = {
+	["all"] = { targetType = RELOAD_TYPE_ALL, name = "all" },
+
+	["action"] = { targetType = RELOAD_TYPE_ACTIONS, name = "actions" },
+	["actions"] = { targetType = RELOAD_TYPE_ACTIONS, name = "actions" },
+
+	["chat"] = { targetType = RELOAD_TYPE_CHAT, name = "chatchannels" },
+	["channel"] = { targetType = RELOAD_TYPE_CHAT, name = "chatchannels" },
+	["chatchannels"] = { targetType = RELOAD_TYPE_CHAT, name = "chatchannels" },
+
+	["config"] = { targetType = RELOAD_TYPE_CONFIG, name = "config" },
+	["configuration"] = { targetType = RELOAD_TYPE_CONFIG, name = "config" },
+
+	["creaturescript"] = { targetType = RELOAD_TYPE_CREATURESCRIPTS, name = "creature scripts" },
+	["creaturescripts"] = { targetType = RELOAD_TYPE_CREATURESCRIPTS, name = "creature scripts" },
+
+	["events"] = { targetType = RELOAD_TYPE_EVENTS, name = "events" },
+
+	["global"] = { targetType = RELOAD_TYPE_GLOBAL, name = "global.lua" },
+
+	["globalevent"] = { targetType = RELOAD_TYPE_GLOBALEVENTS, name = "globalevents" },
+	["globalevents"] = { targetType = RELOAD_TYPE_GLOBALEVENTS, name = "globalevents" },
+
+	["items"] = { targetType = RELOAD_TYPE_ITEMS, name = "items" },
+
+	["monster"] = { targetType = RELOAD_TYPE_MONSTERS, name = "monsters" },
+	["monsters"] = { targetType = RELOAD_TYPE_MONSTERS, name = "monsters" },
+
+	["move"] = { targetType = RELOAD_TYPE_MOVEMENTS, name = "movements" },
+	["movement"] = { targetType = RELOAD_TYPE_MOVEMENTS, name = "movements" },
+	["movements"] = { targetType = RELOAD_TYPE_MOVEMENTS, name = "movements" },
+
+	["npc"] = { targetType = RELOAD_TYPE_NPCS, name = "npcs" },
+	["npcs"] = { targetType = RELOAD_TYPE_NPCS, name = "npcs" },
+
+	["raid"] = { targetType = RELOAD_TYPE_RAIDS, name = "raids" },
+	["raids"] = { targetType = RELOAD_TYPE_RAIDS, name = "raids" },
+
+	["spell"] = { targetType = RELOAD_TYPE_SPELLS, name = "spells" },
+	["spells"] = { targetType = RELOAD_TYPE_SPELLS, name = "spells" },
+
+	["talk"] = { targetType = RELOAD_TYPE_TALKACTIONS, name = "talk actions" },
+	["talkaction"] = { targetType = RELOAD_TYPE_TALKACTIONS, name = "talk actions" },
+	["talkactions"] = { targetType = RELOAD_TYPE_TALKACTIONS, name = "talk actions" }
+}
+
+function onSay(player, words, param)
+	if not player:getGroup():getAccess() then
+		return true
+	end
+
+	if player:getAccountType() < ACCOUNT_TYPE_GAMEMASTER then
+		return false
+	end
+
+	local reloadType = reloadTypes[param and param:lower()]
+	if not reloadType then
+		player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Reload type not found.")
+		return false
+	end
+
+	Game.reload(reloadType.targetType)
+	player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, string.format("Reloaded %s.", reloadType.name))
+	return true
+end
\ No newline at end of file
diff --git a/data/talkactions/scripts/save.lua b/data/talkactions/scripts/save.lua
new file mode 100644
index 0000000..d704c4c
--- /dev/null
+++ b/data/talkactions/scripts/save.lua
@@ -0,0 +1,23 @@
+function onSay(player, words, param)
+
+	local function timeSave(delay, msg)
+		broadcastMessage(msg, MESSAGE_STATUS_WARNING)
+		player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, msg)
+		addEvent(saveServer, delay)
+	end
+
+    if not player:getGroup():getAccess() then
+		return true
+	end
+
+	if player:getAccountType() < ACCOUNT_TYPE_GOD then
+		return false
+	end
+
+	if isNumber(param) then
+		local delay = tonumber(param) * 1000
+		timeSave(delay, "Saving server in " .. tonumber(param) .. " seconds.")
+	else
+		saveServer()
+	end
+end
\ No newline at end of file
diff --git a/data/talkactions/scripts/sellhouse.lua b/data/talkactions/scripts/sellhouse.lua
new file mode 100644
index 0000000..9920a8a
--- /dev/null
+++ b/data/talkactions/scripts/sellhouse.lua
@@ -0,0 +1,19 @@
+function onSay(player, words, param)
+	local tradePartner = Player(param)
+	if not tradePartner or tradePartner == player then
+		player:sendCancelMessage("Trade player not found.")
+		return false
+	end
+
+	local house = player:getTile():getHouse()
+	if not house then
+		player:sendCancelMessage("You must stand in your house to initiate the trade.")
+		return false
+	end
+
+	local returnValue = house:startTrade(player, tradePartner)
+	if returnValue ~= RETURNVALUE_NOERROR then
+		player:sendCancelMessage(returnValue)
+	end
+	return false
+end
\ No newline at end of file
diff --git a/data/talkactions/talkactions.xml b/data/talkactions/talkactions.xml
index ad15b22..ac214b4 100644
--- a/data/talkactions/talkactions.xml
+++ b/data/talkactions/talkactions.xml
@@ -27,7 +27,9 @@
 	
 	
 	
-	
+  
+  
+  
 	
 	
 	
@@ -37,6 +39,7 @@
 	
 	
 	
+  
 	
 	
 	
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6ccc19f..76c0cad 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -7,7 +7,6 @@ set(tfs_SRC
 	${CMAKE_CURRENT_LIST_DIR}/behaviourdatabase.cpp
 	${CMAKE_CURRENT_LIST_DIR}/chat.cpp
 	${CMAKE_CURRENT_LIST_DIR}/combat.cpp
-	${CMAKE_CURRENT_LIST_DIR}/commands.cpp
 	${CMAKE_CURRENT_LIST_DIR}/condition.cpp
 	${CMAKE_CURRENT_LIST_DIR}/configmanager.cpp
 	${CMAKE_CURRENT_LIST_DIR}/connection.cpp
@@ -19,6 +18,7 @@ set(tfs_SRC
 	${CMAKE_CURRENT_LIST_DIR}/databasemanager.cpp
 	${CMAKE_CURRENT_LIST_DIR}/databasetasks.cpp
 	${CMAKE_CURRENT_LIST_DIR}/depotlocker.cpp
+	${CMAKE_CURRENT_LIST_DIR}/events.cpp
 	${CMAKE_CURRENT_LIST_DIR}/fileloader.cpp
 	${CMAKE_CURRENT_LIST_DIR}/game.cpp
 	${CMAKE_CURRENT_LIST_DIR}/globalevent.cpp
diff --git a/src/account.h b/src/account.h
index a7741f4..5bdc53a 100644
--- a/src/account.h
+++ b/src/account.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/actions.cpp b/src/actions.cpp
index 748bcab..439748d 100644
--- a/src/actions.cpp
+++ b/src/actions.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/actions.h b/src/actions.h
index 02c4924..f4ae6d9 100644
--- a/src/actions.h
+++ b/src/actions.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/ban.cpp b/src/ban.cpp
index a531ea9..547ad29 100644
--- a/src/ban.cpp
+++ b/src/ban.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/ban.h b/src/ban.h
index 0ca2360..86535a6 100644
--- a/src/ban.h
+++ b/src/ban.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/baseevents.cpp b/src/baseevents.cpp
index f8191fc..c99243e 100644
--- a/src/baseevents.cpp
+++ b/src/baseevents.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/baseevents.h b/src/baseevents.h
index 3529a6a..c5b528f 100644
--- a/src/baseevents.h
+++ b/src/baseevents.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/bed.cpp b/src/bed.cpp
index a2f55aa..90629a9 100644
--- a/src/bed.cpp
+++ b/src/bed.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/bed.h b/src/bed.h
index b45486d..f1f836d 100644
--- a/src/bed.h
+++ b/src/bed.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/behaviourdatabase.cpp b/src/behaviourdatabase.cpp
index 7ddc588..e331abb 100644
--- a/src/behaviourdatabase.cpp
+++ b/src/behaviourdatabase.cpp
@@ -1,6 +1,6 @@
 /**
 * Tibia GIMUD Server - a free and open-source MMORPG server emulator
-* Copyright (C) 2017  Alejandro Mujica 
+* Copyright (C) 2019 Sabrehaven and Mark Samman 
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -820,10 +820,6 @@ void BehaviourDatabase::checkAction(const NpcBehaviourAction* action, Player* pl
 				}
 			} while (amount);
 		} else {
-			if (it.charges) {
-				data = it.charges;
-			}
-
 			for (int32_t i = 0; i < std::max(1, amount); i++) {
 				Item* item = Item::CreateItem(itemId, data);
 				if (!item) {
@@ -937,7 +933,7 @@ void BehaviourDatabase::checkAction(const NpcBehaviourAction* action, Player* pl
 	}
 	case BEHAVIOUR_TYPE_EXPERIENCE: {
 		int32_t experience = evaluate(action->expression, player, message);
-		player->addExperience(experience, true, false);
+		player->addExperience(nullptr, experience, false);
 		break;
 	}
 	case BEHAVIOUR_TYPE_WITHDRAW: {
diff --git a/src/behaviourdatabase.h b/src/behaviourdatabase.h
index 73e1856..de7eca6 100644
--- a/src/behaviourdatabase.h
+++ b/src/behaviourdatabase.h
@@ -1,6 +1,6 @@
 /**
 * Tibia GIMUD Server - a free and open-source MMORPG server emulator
-* Copyright (C) 2017  Alejandro Mujica 
+* Copyright (C) 2019 Sabrehaven and Mark Samman 
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
diff --git a/src/chat.cpp b/src/chat.cpp
index bee075e..59973c8 100644
--- a/src/chat.cpp
+++ b/src/chat.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/chat.h b/src/chat.h
index 3d7b973..e181142 100644
--- a/src/chat.h
+++ b/src/chat.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/combat.cpp b/src/combat.cpp
index 2e62e91..52bc2da 100644
--- a/src/combat.cpp
+++ b/src/combat.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,13 +24,16 @@
 #include "game.h"
 #include "configmanager.h"
 #include "monster.h"
+#include "events.h"
 
 extern Game g_game;
 extern ConfigManager g_config;
+extern Events* g_events;
 
 CombatDamage Combat::getCombatDamage(Creature* creature) const
 {
 	CombatDamage damage;
+	damage.origin = params.origin;
 	damage.type = params.combatType;
 	if (formulaType == COMBAT_FORMULA_DAMAGE) {
 		damage.min = static_cast(mina);
@@ -175,11 +178,7 @@ ReturnValue Combat::canDoCombat(Creature* caster, Tile* tile, bool aggressive)
 		return RETURNVALUE_NOTENOUGHROOM;
 	}
 
-	/*if (tile->hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID) && tile->hasProperty(CONST_PROP_UNLAY)) {
-		return RETURNVALUE_NOTENOUGHROOM;
-	}*/
-
-	if (tile->hasProperty(CONST_PROP_IMMOVABLEBLOCKPATH) && tile->hasProperty(CONST_PROP_IMMOVABLENOFIELDBLOCKPATH)) {
+	if (tile->hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID) && tile->hasProperty(CONST_PROP_UNLAY)) {
 		return RETURNVALUE_NOTENOUGHROOM;
 	}
 
@@ -192,7 +191,8 @@ ReturnValue Combat::canDoCombat(Creature* caster, Tile* tile, bool aggressive)
 		const Position& tilePosition = tile->getPosition();
 		if (casterPosition.z < tilePosition.z) {
 			return RETURNVALUE_FIRSTGODOWNSTAIRS;
-		} else if (casterPosition.z > tilePosition.z) {
+		}
+		else if (casterPosition.z > tilePosition.z) {
 			return RETURNVALUE_FIRSTGOUPSTAIRS;
 		}
 
@@ -208,7 +208,7 @@ ReturnValue Combat::canDoCombat(Creature* caster, Tile* tile, bool aggressive)
 		return RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE;
 	}
 
-	return RETURNVALUE_NOERROR;
+	return g_events->eventCreatureOnAreaCombat(caster, tile, aggressive);
 }
 
 bool Combat::isInPvpZone(const Creature* attacker, const Creature* target)
@@ -232,74 +232,78 @@ bool Combat::isProtected(const Player* attacker, const Player* target)
 
 ReturnValue Combat::canDoCombat(Creature* attacker, Creature* target)
 {
-	if (attacker) {
-		if (const Player* targetPlayer = target->getPlayer()) {
-			if (targetPlayer->hasFlag(PlayerFlag_CannotBeAttacked)) {
+	if (!attacker) {
+		return g_events->eventCreatureOnTargetCombat(attacker, target);
+	}
+
+	if (const Player* targetPlayer = target->getPlayer()) {
+		if (targetPlayer->hasFlag(PlayerFlag_CannotBeAttacked)) {
+			return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
+		}
+
+		if (const Player* attackerPlayer = attacker->getPlayer()) {
+			if (attackerPlayer->hasFlag(PlayerFlag_CannotAttackPlayer)) {
 				return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
 			}
 
-			if (const Player* attackerPlayer = attacker->getPlayer()) {
-				if (attackerPlayer->hasFlag(PlayerFlag_CannotAttackPlayer)) {
-					return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
-				}
-
-				if (isProtected(attackerPlayer, targetPlayer)) {
-					return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
-				}
-
-				//nopvp-zone
-				const Tile* targetPlayerTile = targetPlayer->getTile();
-				if (targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE)) {
-					return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
-				} else if (attackerPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE) && !targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE | TILESTATE_PROTECTIONZONE)) {
-					return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
-				}
+			if (isProtected(attackerPlayer, targetPlayer)) {
+				return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
 			}
 
-			if (attacker->isSummon()) {
-				if (const Player* masterAttackerPlayer = attacker->getMaster()->getPlayer()) {
-					if (masterAttackerPlayer->hasFlag(PlayerFlag_CannotAttackPlayer)) {
-						return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
-					}
-
-					if (targetPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE)) {
-						return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
-					}
-
-					if (isProtected(masterAttackerPlayer, targetPlayer)) {
-						return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
-					}
-				}
+			//nopvp-zone
+			const Tile* targetPlayerTile = targetPlayer->getTile();
+			if (targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE)) {
+				return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
 			}
-		} else if (target->getMonster()) {
-			if (const Player* attackerPlayer = attacker->getPlayer()) {
-				if (attackerPlayer->hasFlag(PlayerFlag_CannotAttackMonster)) {
-					return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
-				}
-
-				if (target->isSummon() && target->getMaster()->getPlayer() && target->getZone() == ZONE_NOPVP) {
-					return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
-				}
+			else if (attackerPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE) && !targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE | TILESTATE_PROTECTIONZONE)) {
+				return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
 			}
 		}
 
-		if (g_game.getWorldType() == WORLD_TYPE_NO_PVP) {
-			if (attacker->getPlayer() || (attacker->isSummon() && attacker->getMaster()->getPlayer())) {
-				if (target->getPlayer()) {
-					if (!isInPvpZone(attacker, target)) {
-						return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
-					}
+		if (attacker->isSummon()) {
+			if (const Player* masterAttackerPlayer = attacker->getMaster()->getPlayer()) {
+				if (masterAttackerPlayer->hasFlag(PlayerFlag_CannotAttackPlayer)) {
+					return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
 				}
 
-				if (target->isSummon() && target->getMaster()->getPlayer()) {
-					if (!isInPvpZone(attacker, target)) {
-						return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
-					}
+				if (targetPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE)) {
+					return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
+				}
+
+				if (isProtected(masterAttackerPlayer, targetPlayer)) {
+					return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
 				}
 			}
 		}
 	}
-	return RETURNVALUE_NOERROR;
+	else if (target->getMonster()) {
+		if (const Player* attackerPlayer = attacker->getPlayer()) {
+			if (attackerPlayer->hasFlag(PlayerFlag_CannotAttackMonster)) {
+				return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
+			}
+
+			if (target->isSummon() && target->getMaster()->getPlayer() && target->getZone() == ZONE_NOPVP) {
+				return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
+			}
+		}
+	}
+
+	if (g_game.getWorldType() == WORLD_TYPE_NO_PVP) {
+		if (attacker->getPlayer() || (attacker->isSummon() && attacker->getMaster()->getPlayer())) {
+			if (target->getPlayer()) {
+				if (!isInPvpZone(attacker, target)) {
+					return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
+				}
+			}
+
+			if (target->isSummon() && target->getMaster()->getPlayer()) {
+				if (!isInPvpZone(attacker, target)) {
+					return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
+				}
+			}
+		}
+	}
+	return g_events->eventCreatureOnTargetCombat(attacker, target);
 }
 
 void Combat::setPlayerCombatValues(formulaType_t formulaType, double mina, double minb, double maxa, double maxb)
@@ -422,7 +426,7 @@ CallBack* Combat::getCallback(CallBackParam_t key)
 	return nullptr;
 }
 
-bool Combat::CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data)
+void Combat::CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data)
 {
 	assert(data);
 	CombatDamage damage = *data;
@@ -439,18 +443,16 @@ bool Combat::CombatHealthFunc(Creature* caster, Creature* target, const CombatPa
 	}
 
 	if (g_game.combatBlockHit(damage, caster, target, params.blockedByShield, params.blockedByArmor, params.itemId != 0)) {
-		return false;
+		return;
 	}
 
 	if (g_game.combatChangeHealth(caster, target, damage)) {
-		CombatConditionFunc(caster, target, params, nullptr);
+		CombatConditionFunc(caster, target, params, &damage);
 		CombatDispelFunc(caster, target, params, nullptr);
 	}
-
-	return true;
 }
 
-bool Combat::CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data)
+void Combat::CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data)
 {
 	assert(data);
 	CombatDamage damage = *data;
@@ -465,16 +467,18 @@ bool Combat::CombatManaFunc(Creature* caster, Creature* target, const CombatPara
 		}
 	}
 
-	if (g_game.combatChangeMana(caster, target, damage.value)) {
+	if (g_game.combatChangeMana(caster, target, damage)) {
 		CombatConditionFunc(caster, target, params, nullptr);
 		CombatDispelFunc(caster, target, params, nullptr);
 	}
-
-	return true;
 }
 
-bool Combat::CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage*)
+void Combat::CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data)
 {
+	if (params.origin == ORIGIN_MELEE && data && data->value == 0) {
+		return;
+	}
+
 	for (const auto& condition : params.conditionList) {
 		if (caster == target || !target->isImmune(condition->getType())) {
 			Condition* conditionCopy = condition->clone();
@@ -486,21 +490,17 @@ bool Combat::CombatConditionFunc(Creature* caster, Creature* target, const Comba
 			target->addCombatCondition(conditionCopy);
 		}
 	}
-
-	return true;
 }
 
-bool Combat::CombatDispelFunc(Creature*, Creature* target, const CombatParams& params, CombatDamage*)
+void Combat::CombatDispelFunc(Creature*, Creature* target, const CombatParams& params, CombatDamage*)
 {
 	target->removeCombatCondition(params.dispelType);
-	return true;
 }
 
-bool Combat::CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage*)
+void Combat::CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage*)
 {
 	CombatConditionFunc(caster, target, params, nullptr);
 	CombatDispelFunc(caster, target, params, nullptr);
-	return true;
 }
 
 void Combat::combatTileEffects(const SpectatorVec& list, Creature* caster, Tile* tile, const CombatParams& params)
@@ -632,6 +632,8 @@ void Combat::CombatFunc(Creature* caster, const Position& pos, const AreaCombat*
 	const int32_t rangeY = maxY + Map::maxViewportY;
 	g_game.map.getSpectators(list, pos, true, true, rangeX, rangeX, rangeY, rangeY);
 
+	postCombatEffects(caster, pos, params);
+
 	uint16_t decreasedDamage = 0;
 	const uint16_t maximumDecreasedDamage = params.maximumDecreasedDamage;
 
@@ -721,6 +723,8 @@ void Combat::CombatFunc(Creature* caster, const Position& pos, const AreaCombat*
 			continue;
 		}
 
+		combatTileEffects(list, caster, tile, params);
+
 		if (CreatureVector* creatures = tile->getCreatures()) {
 			const Creature* topCreature = tile->getTopCreature();
 			for (Creature* creature : *creatures) {
@@ -746,9 +750,7 @@ void Combat::CombatFunc(Creature* caster, const Position& pos, const AreaCombat*
 				}
 			}
 		}
-		combatTileEffects(list, caster, tile, params);
 	}
-	postCombatEffects(caster, pos, params);
 }
 
 void Combat::doCombat(Creature* caster, Creature* target) const
@@ -834,7 +836,7 @@ bool Combat::attack(Creature* attacker, Creature* target)
 	return false;
 }
 
-bool Combat::closeAttack(Creature* attacker, Creature* target, fightMode_t fightMode, bool fist)
+bool Combat::closeAttack(Creature* attacker, Creature* target, fightMode_t fightMode)
 {
 	const Position& attackerPos = attacker->getPosition();
 	const Position& targetPos = target->getPosition();
@@ -859,7 +861,7 @@ bool Combat::closeAttack(Creature* attacker, Creature* target, fightMode_t fight
 	uint32_t skillValue = 0;
 	uint8_t skill = SKILL_FIST;
 
-	Combat::getAttackValue(attacker, attackValue, skillValue, skill, fist);
+	Combat::getAttackValue(attacker, attackValue, skillValue, skill);
 
 	int32_t defense = target->getDefense();
 
@@ -876,6 +878,7 @@ bool Combat::closeAttack(Creature* attacker, Creature* target, fightMode_t fight
 	combatDamage.type = combatParams.combatType;
 	int32_t totalDamage = Combat::getTotalDamage(skillValue, attackValue, fightMode);
 	combatDamage.value = totalDamage;
+	combatDamage.origin = ORIGIN_MELEE;
 
 	bool hit = Combat::doCombatHealth(attacker, target, combatDamage, combatParams);
 
@@ -884,7 +887,7 @@ bool Combat::closeAttack(Creature* attacker, Creature* target, fightMode_t fight
 		if (poison) {
 			int32_t randTest = rand();
 
-			if (hit || -totalDamage > defense && (randTest == 5 * (randTest / 5))) {
+			if (hit || ((-totalDamage > defense) && (randTest == 5 * (randTest / 5)))) {
 				poison = normal_random(poison / 2, poison);
 				if (poison) {
 					ConditionDamage* condition = static_cast(Condition::createCondition(CONDITIONID_COMBAT, CONDITION_POISON, 0, 0));
@@ -962,9 +965,9 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
 		if (weapon->getWeaponType() == WEAPON_DISTANCE) {
 			ammunition = player->getAmmunition();
 			if (weapon->getAmmoType() != AMMO_NONE) {
-				if (!ammunition || ammunition->getWeaponType() != WEAPON_AMMO || weapon->getAmmoType() != ammunition->getAmmoType()) {
+				if (!ammunition || weapon->getAmmoType() != ammunition->getAmmoType()) {
 					// redirect to fist fighting
-					return closeAttack(attacker, target, fightMode, true);
+					return closeAttack(attacker, target, fightMode);
 				}
 
 				distanceEffect = ammunition->getMissileType();
@@ -991,6 +994,7 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
 		CombatDamage combatDamage;
 		combatDamage.type = combatParams.combatType;
 		combatDamage.value = Combat::getTotalDamage(skillValue, attackValue, fightMode);
+		combatDamage.origin = ORIGIN_RANGED;
 
 		if (weapon) {
 			hitChance = 75; // throwables and such
@@ -1011,7 +1015,7 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
 			}
 		}
 
-		if (ammunition && ammunition->getWeaponType() == WEAPON_AMMO && weapon->getAmmoType() != AMMO_NONE && weapon->getAmmoType() == ammunition->getAmmoType()) {
+		if (ammunition && weapon->getAmmoType() != AMMO_NONE && weapon->getAmmoType() == ammunition->getAmmoType()) {
 			hitChance = 90; // bows and crossbows
 			specialEffect = ammunition->getWeaponSpecialEffect();
 			attackStrength = ammunition->getAttackStrength();
@@ -1037,10 +1041,12 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
 
 		bool hit = false;
 
-		if (rand() % distance <= skillValue) {
-			hit = rand() % 100 <= hitChance;
+		int32_t random = rand();
+		if (random % distance <= static_cast(skillValue)) {
+			hit = random % 100 <= hitChance;
 		}
 
+
 		if (Player* player = attacker->getPlayer()) {
 			if (player->getAddAttackSkill()) {
 				switch (player->getLastAttackBlockType()) {
@@ -1130,6 +1136,7 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
 		CombatDamage combatDamage;
 		combatDamage.type = combatParams.combatType;
 		combatDamage.value = -(variation + weapon->getAttackStrength());
+		combatDamage.origin = ORIGIN_RANGED;
 
 		g_game.addDistanceEffect(attackerPos, targetPos, distanceEffect);
 		Combat::doCombatHealth(attacker, target, combatDamage, combatParams);
@@ -1182,13 +1189,13 @@ void Combat::circleShapeSpell(Creature* attacker, const Position& toPos, int32_t
 	}
 }
 
-void Combat::getAttackValue(Creature* creature, uint32_t& attackValue, uint32_t& skillValue, uint8_t& skill, bool fist)
+void Combat::getAttackValue(Creature* creature, uint32_t& attackValue, uint32_t& skillValue, uint8_t& skill)
 {
 	skill = SKILL_FIST;
 
 	if (Player* player = creature->getPlayer()) {
 		Item* weapon = player->getWeapon();
-		if (weapon && !fist) {
+		if (weapon) {
 			switch (weapon->getWeaponType()) {
 			case WEAPON_AXE: {
 				skill = SKILL_AXE;
@@ -1243,7 +1250,7 @@ bool Combat::canUseWeapon(Player* player, Item* weapon)
 		return false;
 	}
 
-	if (!player->hasFlag(PlayerFlag_HasInfiniteMana) && player->getMana() < weapon->getManaConsumption()) {
+	if (!player->hasFlag(PlayerFlag_HasInfiniteMana) && static_cast(player->getMana()) < weapon->getManaConsumption()) {
 		return false;
 	}
 
@@ -1278,14 +1285,14 @@ bool Combat::doCombatHealth(Creature* caster, Creature* target, CombatDamage& da
 	}
 
 	if (canCombat) {
-		canCombat = CombatHealthFunc(caster, target, params, &damage);
-		if (params.targetCallback) {
-			params.targetCallback->onTargetCombat(caster, target);
-		}
-
 		if (caster && params.distanceEffect != CONST_ANI_NONE) {
 			addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
 		}
+
+		CombatHealthFunc(caster, target, params, &damage);
+		if (params.targetCallback) {
+			params.targetCallback->onTargetCombat(caster, target);
+		}
 	}
 
 	return canCombat;
@@ -1304,14 +1311,14 @@ void Combat::doCombatMana(Creature* caster, Creature* target, CombatDamage& dama
 	}
 
 	if (canCombat) {
+		if (caster && params.distanceEffect != CONST_ANI_NONE) {
+			addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
+		}
+
 		CombatManaFunc(caster, target, params, &damage);
 		if (params.targetCallback) {
 			params.targetCallback->onTargetCombat(caster, target);
 		}
-
-		if (caster && params.distanceEffect != CONST_ANI_NONE) {
-			addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
-		}
 	}
 }
 
@@ -1333,14 +1340,14 @@ void Combat::doCombatCondition(Creature* caster, Creature* target, const CombatP
 	}
 
 	if (canCombat) {
+		if (caster && params.distanceEffect != CONST_ANI_NONE) {
+			addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
+		}
+
 		CombatConditionFunc(caster, target, params, nullptr);
 		if (params.targetCallback) {
 			params.targetCallback->onTargetCombat(caster, target);
 		}
-
-		if (caster && params.distanceEffect != CONST_ANI_NONE) {
-			addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
-		}
 	}
 }
 
diff --git a/src/combat.h b/src/combat.h
index bc07037..a6b6b70 100644
--- a/src/combat.h
+++ b/src/combat.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -73,6 +73,7 @@ struct CombatParams {
 
 	ConditionType_t dispelType = CONDITION_NONE;
 	CombatType_t combatType = COMBAT_NONE;
+	CombatOrigin origin = ORIGIN_SPELL;
 
 	uint8_t impactEffect = CONST_ME_NONE;
 	uint8_t distanceEffect = CONST_ANI_NONE;
@@ -116,7 +117,7 @@ struct DunkenImpact : Impact
 	void handleCreature(Creature* target) final;
 };
 
-typedef bool (*COMBATFUNC)(Creature*, Creature*, const CombatParams&, CombatDamage*);
+typedef void(*COMBATFUNC)(Creature*, Creature*, const CombatParams&, CombatDamage*);
 
 class MatrixArea
 {
@@ -285,12 +286,12 @@ class Combat
 		static int32_t getTotalDamage(int32_t attackSkill, int32_t attackValue, fightMode_t fightMode);
 
 		static bool attack(Creature* attacker, Creature* target);
-		static bool closeAttack(Creature* attacker, Creature* target, fightMode_t fightMode, bool fist = false);
+		static bool closeAttack(Creature* attacker, Creature* target, fightMode_t fightMode);
 		static bool rangeAttack(Creature* attacker, Creature* target, fightMode_t fightMode);
 
 		static void circleShapeSpell(Creature* attacker, const Position& toPos, int32_t range, int32_t animation, int32_t radius, DamageImpact* impact, int32_t effect);
 
-		static void getAttackValue(Creature* creature, uint32_t& attackValue, uint32_t& skillValue, uint8_t& skill, bool fist = false);
+		static void getAttackValue(Creature* creature, uint32_t& attackValue, uint32_t& skillValue, uint8_t& skill);
 
 		static bool doCombatHealth(Creature* caster, Creature* target, CombatDamage& damage, const CombatParams& params);
 		static void doCombatHealth(Creature* caster, const Position& position, const AreaCombat* area, CombatDamage& damage, const CombatParams& params);
@@ -339,6 +340,10 @@ class Combat
 			postCombatEffects(caster, pos, params);
 		}
 
+		void setOrigin(CombatOrigin origin) {
+			params.origin = origin;
+		}
+
 	protected:
 		static bool canUseWeapon(Player* player, Item* weapon);
 		static void postWeaponEffects(Player* player, Item* weapon);
@@ -347,11 +352,11 @@ class Combat
 
 		static void CombatFunc(Creature* caster, const Position& pos, const AreaCombat* area, const CombatParams& params, COMBATFUNC func, CombatDamage* data);
 
-		static bool CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
-		static bool CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* damage);
-		static bool CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
-		static bool CombatDispelFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
-		static bool CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
+		static void CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
+		static void CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* damage);
+		static void CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
+		static void CombatDispelFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
+		static void CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
 
 		static void combatTileEffects(const SpectatorVec& list, Creature* caster, Tile* tile, const CombatParams& params);
 		CombatDamage getCombatDamage(Creature* creature) const;
diff --git a/src/commands.cpp b/src/commands.cpp
index 0e42920..83db35e 100644
--- a/src/commands.cpp
+++ b/src/commands.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/commands.h b/src/commands.h
index 2be9ac1..828ef8a 100644
--- a/src/commands.h
+++ b/src/commands.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/condition.cpp b/src/condition.cpp
index e07d8d5..13b02cd 100644
--- a/src/condition.cpp
+++ b/src/condition.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -227,7 +227,7 @@ bool Condition::isPersistent() const
 		return false;
 	}
 
-	if (!(id == CONDITIONID_DEFAULT || id == CONDITIONID_COMBAT)) {
+	if (!(id == CONDITIONID_DEFAULT || id == CONDITIONID_COMBAT || conditionType == CONDITION_MUTED)) {
 		return false;
 	}
 
@@ -655,7 +655,9 @@ bool ConditionRegeneration::executeCondition(Creature* creature, int32_t interva
 
 		if (internalManaTicks >= manaTicks) {
 			internalManaTicks = 0;
-			creature->changeMana(manaGain);
+			if (Player* player = creature->getPlayer()) {
+				player->changeMana(manaGain);
+			}
 		}
 	}
 
@@ -756,8 +758,6 @@ bool ConditionSoul::setParam(ConditionParam_t param, int32_t value)
 
 bool ConditionDamage::setParam(ConditionParam_t param, int32_t value)
 {
-	Condition::setParam(param, value);
-
 	switch (param) {
 		case CONDITION_PARAM_OWNER:
 			owner = value;
@@ -927,6 +927,7 @@ bool ConditionDamage::doDamage(Creature* creature, int32_t healthChange)
 	}
 
 	CombatDamage damage;
+	damage.origin = ORIGIN_CONDITION;
 	damage.value = healthChange;
 	damage.type = Combat::ConditionToDamageType(conditionType);
 
diff --git a/src/condition.h b/src/condition.h
index efee824..2535aa0 100644
--- a/src/condition.h
+++ b/src/condition.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/configmanager.cpp b/src/configmanager.cpp
index d1e60c4..2993702 100644
--- a/src/configmanager.cpp
+++ b/src/configmanager.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -77,7 +77,9 @@ bool ConfigManager::load()
 	boolean[CONVERT_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "convertUnsafeScripts", true);
 	boolean[TELEPORT_NEWBIES] = getGlobalBoolean(L, "teleportNewbies", true);
 	boolean[STACK_CUMULATIVES] = getGlobalBoolean(L, "autoStackCumulatives", false);
-	boolean[QUERY_PLAYER_CONTAINERS] = getGlobalBoolean(L, "queryPlayerContainers", false);
+	boolean[BLOCK_HEIGHT] = getGlobalBoolean(L, "blockHeight", false);
+	boolean[DROP_ITEMS] = getGlobalBoolean(L, "dropItems", false);
+
 
 	string[DEFAULT_PRIORITY] = getGlobalString(L, "defaultPriority", "high");
 	string[SERVER_NAME] = getGlobalString(L, "serverName", "");
diff --git a/src/configmanager.h b/src/configmanager.h
index f2105fe..6c14b68 100644
--- a/src/configmanager.h
+++ b/src/configmanager.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -40,7 +40,8 @@ class ConfigManager
 			CONVERT_UNSAFE_SCRIPTS,
 			TELEPORT_NEWBIES,
 			STACK_CUMULATIVES,
-			QUERY_PLAYER_CONTAINERS,
+			BLOCK_HEIGHT,
+			DROP_ITEMS,
 
 			LAST_BOOLEAN_CONFIG /* this must be the last one */
 		};
diff --git a/src/connection.cpp b/src/connection.cpp
index 5f21835..859066c 100644
--- a/src/connection.cpp
+++ b/src/connection.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/connection.h b/src/connection.h
index 34c6ac9..b885749 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/const.h b/src/const.h
index afefe77..8490b1f 100644
--- a/src/const.h
+++ b/src/const.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -308,6 +308,28 @@ enum PlayerFlags : uint64_t {
 	PlayerFlag_SpecialMoveUse = static_cast(1) << 38,
 };
 
+enum ReloadTypes_t : uint8_t {
+	RELOAD_TYPE_ALL,
+	RELOAD_TYPE_ACTIONS,
+	RELOAD_TYPE_CHAT,
+	RELOAD_TYPE_COMMANDS,
+	RELOAD_TYPE_CONFIG,
+	RELOAD_TYPE_CREATURESCRIPTS,
+	RELOAD_TYPE_EVENTS,
+	RELOAD_TYPE_GLOBAL,
+	RELOAD_TYPE_GLOBALEVENTS,
+	RELOAD_TYPE_ITEMS,
+	RELOAD_TYPE_MONSTERS,
+	RELOAD_TYPE_MOUNTS,
+	RELOAD_TYPE_MOVEMENTS,
+	RELOAD_TYPE_NPCS,
+	RELOAD_TYPE_QUESTS,
+	RELOAD_TYPE_RAIDS,
+	RELOAD_TYPE_SPELLS,
+	RELOAD_TYPE_TALKACTIONS,
+	RELOAD_TYPE_WEAPONS,
+};
+
 static constexpr int32_t CHANNEL_GUILD = 0x00;
 static constexpr int32_t CHANNEL_PARTY = 0x01;
 static constexpr int32_t CHANNEL_RULE_REP = 0x02;
diff --git a/src/container.cpp b/src/container.cpp
index e404695..f949f81 100644
--- a/src/container.cpp
+++ b/src/container.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -370,7 +370,7 @@ ReturnValue Container::queryRemove(const Thing& thing, uint32_t count, uint32_t
 }
 
 Cylinder* Container::queryDestination(int32_t& index, const Thing &thing, Item** destItem,
-		uint32_t& flags)
+	uint32_t& flags)
 {
 	if (index == 254 /*move up*/) {
 		index = INDEX_WHEREEVER;
@@ -386,7 +386,8 @@ Cylinder* Container::queryDestination(int32_t& index, const Thing &thing, Item**
 	if (index == 255 /*add wherever*/) {
 		index = INDEX_WHEREEVER;
 		*destItem = nullptr;
-	} else if (index >= static_cast(capacity())) {
+	}
+	else if (index >= static_cast(capacity())) {
 		/*
 		if you have a container, maximize it to show all 20 slots
 		then you open a bag that is inside the container you will have a bag with 8 slots
@@ -403,6 +404,20 @@ Cylinder* Container::queryDestination(int32_t& index, const Thing &thing, Item**
 		return this;
 	}
 
+	if (index != INDEX_WHEREEVER) {
+		Item* itemFromIndex = getItemByIndex(index);
+		if (itemFromIndex) {
+			*destItem = itemFromIndex;
+		}
+
+		Cylinder* subCylinder = dynamic_cast(*destItem);
+		if (subCylinder) {
+			index = INDEX_WHEREEVER;
+			*destItem = nullptr;
+			return subCylinder;
+		}
+	}
+
 	if (g_config.getBoolean(ConfigManager::STACK_CUMULATIVES)) {
 		bool autoStack = !hasBitSet(FLAG_IGNOREAUTOSTACK, flags);
 		if (autoStack && item->isStackable() && item->getParent() != this) {
@@ -419,19 +434,6 @@ Cylinder* Container::queryDestination(int32_t& index, const Thing &thing, Item**
 		}
 	}
 
-	if (index != INDEX_WHEREEVER) {
-		Item* itemFromIndex = getItemByIndex(index);
-		if (itemFromIndex) {
-			*destItem = itemFromIndex;
-		}
-
-		Cylinder* subCylinder = dynamic_cast(*destItem);
-		if (subCylinder) {
-			index = INDEX_WHEREEVER;
-			*destItem = nullptr;
-			return subCylinder;
-		}
-	}
 	return this;
 }
 
diff --git a/src/container.h b/src/container.h
index 7af5675..495c92f 100644
--- a/src/container.h
+++ b/src/container.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/creature.cpp b/src/creature.cpp
index 781c87d..8bd0318 100644
--- a/src/creature.cpp
+++ b/src/creature.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -619,7 +619,8 @@ void Creature::onDeath()
 	if (lastHitCreature) {
 		lastHitUnjustified = lastHitCreature->onKilledCreature(this);
 		lastHitCreatureMaster = lastHitCreature->getMaster();
-	} else {
+	}
+	else {
 		lastHitCreatureMaster = nullptr;
 	}
 
@@ -639,8 +640,9 @@ void Creature::onDeath()
 
 			if (attacker != this) {
 				uint64_t gainExp = getGainedExperience(attacker);
-				if (Player* player = attacker->getPlayer()) {
-					Party* party = player->getParty();
+				if (Player* attackerPlayer = attacker->getPlayer()) {
+					attackerPlayer->removeAttacked(getPlayer());
+					Party* party = attackerPlayer->getParty();
 					if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) {
 						attacker = party->getLeader();
 					}
@@ -649,7 +651,8 @@ void Creature::onDeath()
 				auto tmpIt = experienceMap.find(attacker);
 				if (tmpIt == experienceMap.end()) {
 					experienceMap[attacker] = gainExp;
-				} else {
+				}
+				else {
 					tmpIt->second += gainExp;
 				}
 			}
@@ -752,15 +755,6 @@ void Creature::changeHealth(int32_t healthChange, bool sendHealthChange/* = true
 	}
 }
 
-void Creature::changeMana(int32_t manaChange)
-{
-	if (manaChange > 0) {
-		mana += std::min(manaChange, getMaxMana() - mana);
-	} else {
-		mana = std::max(0, mana + manaChange);
-	}
-}
-
 void Creature::gainHealth(Creature* healer, int32_t healthGain)
 {
 	changeHealth(healthGain);
@@ -778,16 +772,6 @@ void Creature::drainHealth(Creature* attacker, int32_t damage)
 	}
 }
 
-void Creature::drainMana(Creature* attacker, int32_t manaLoss)
-{
-	onAttacked();
-	changeMana(-manaLoss);
-
-	if (attacker) {
-		addDamagePoints(attacker, manaLoss);
-	}
-}
-
 BlockType_t Creature::blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
                                bool checkDefense /* = false */, bool checkArmor /* = false */, bool /* field  = false */)
 {
diff --git a/src/creature.h b/src/creature.h
index 39afb11..994556b 100644
--- a/src/creature.h
+++ b/src/creature.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -220,12 +220,6 @@ class Creature : virtual public Thing
 		virtual int32_t getMaxHealth() const {
 			return healthMax;
 		}
-		uint32_t getMana() const {
-			return mana;
-		}
-		virtual uint32_t getMaxMana() const {
-			return 0;
-		}
 
 		const Outfit_t getCurrentOutfit() const {
 			return currentOutfit;
@@ -320,11 +314,9 @@ class Creature : virtual public Thing
 		}
 
 		virtual void changeHealth(int32_t healthChange, bool sendHealthChange = true);
-		virtual void changeMana(int32_t manaChange);
 
 		void gainHealth(Creature* attacker, int32_t healthGain);
 		virtual void drainHealth(Creature* attacker, int32_t damage);
-		virtual void drainMana(Creature* attacker, int32_t manaLoss);
 
 		virtual bool challengeCreature(Creature*) {
 			return false;
@@ -494,7 +486,6 @@ class Creature : virtual public Thing
 		uint32_t blockTicks = 0;
 		uint32_t lastStepCost = 1;
 		uint32_t baseSpeed = 70;
-		uint32_t mana = 0;
 		uint32_t latestKillEvent = 0;
 		int32_t varSpeed = 0;
 		int32_t health = 1000;
diff --git a/src/creatureevent.cpp b/src/creatureevent.cpp
index 990fa64..eb72b28 100644
--- a/src/creatureevent.cpp
+++ b/src/creatureevent.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -177,6 +177,10 @@ bool CreatureEvent::configureEvent(const pugi::xml_node& node)
 		type = CREATURE_EVENT_KILL;
 	} else if (tmpStr == "advance") {
 		type = CREATURE_EVENT_ADVANCE;
+	} else if (tmpStr == "healthchange") {
+		type = CREATURE_EVENT_HEALTHCHANGE;
+	} else if (tmpStr == "manachange") {
+		type = CREATURE_EVENT_MANACHANGE;
 	} else if (tmpStr == "extendedopcode") {
 		type = CREATURE_EVENT_EXTENDED_OPCODE;
 	} else {
@@ -213,6 +217,12 @@ std::string CreatureEvent::getScriptEventName() const
 		case CREATURE_EVENT_ADVANCE:
 			return "onAdvance";
 
+		case CREATURE_EVENT_HEALTHCHANGE:
+			return "onHealthChange";
+
+		case CREATURE_EVENT_MANACHANGE:
+			return "onManaChange";
+
 		case CREATURE_EVENT_EXTENDED_OPCODE:
 			return "onExtendedOpcode";
 
@@ -409,6 +419,85 @@ void CreatureEvent::executeOnKill(Creature* creature, Creature* target)
 	scriptInterface->callVoidFunction(2);
 }
 
+void CreatureEvent::executeHealthChange(Creature* creature, Creature* attacker, CombatDamage& damage)
+{
+	//onHealthChange(creature, attacker, value, type, min, max, origin)
+	if (!scriptInterface->reserveScriptEnv()) {
+		std::cout << "[Error - CreatureEvent::executeHealthChange] Call stack overflow" << std::endl;
+		return;
+	}
+
+	ScriptEnvironment* env = scriptInterface->getScriptEnv();
+	env->setScriptId(scriptId, scriptInterface);
+
+	lua_State* L = scriptInterface->getLuaState();
+	scriptInterface->pushFunction(scriptId);
+
+	LuaScriptInterface::pushUserdata(L, creature);
+	LuaScriptInterface::setCreatureMetatable(L, -1, creature);
+	if (attacker) {
+		LuaScriptInterface::pushUserdata(L, attacker);
+		LuaScriptInterface::setCreatureMetatable(L, -1, attacker);
+	}
+	else {
+		lua_pushnil(L);
+	}
+
+	LuaScriptInterface::pushCombatDamage(L, damage);
+
+	if (scriptInterface->protectedCall(L, 7, 4) != 0) {
+		LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
+	}
+	else {
+		damage.value = std::abs(LuaScriptInterface::getNumber(L, -4));
+		damage.type = LuaScriptInterface::getNumber(L, -3);
+		damage.min = std::abs(LuaScriptInterface::getNumber(L, -2));
+		damage.max = LuaScriptInterface::getNumber(L, -1);
+
+		lua_pop(L, 4);
+		if (damage.type != COMBAT_HEALING) {
+			damage.value = -damage.value;
+		}
+	}
+
+	scriptInterface->resetScriptEnv();
+}
+
+void CreatureEvent::executeManaChange(Creature* creature, Creature* attacker, CombatDamage& damage) {
+	//onManaChange(creature, attacker, value, type, min, max, origin)
+	if (!scriptInterface->reserveScriptEnv()) {
+		std::cout << "[Error - CreatureEvent::executeManaChange] Call stack overflow" << std::endl;
+		return;
+	}
+
+	ScriptEnvironment* env = scriptInterface->getScriptEnv();
+	env->setScriptId(scriptId, scriptInterface);
+
+	lua_State* L = scriptInterface->getLuaState();
+	scriptInterface->pushFunction(scriptId);
+
+	LuaScriptInterface::pushUserdata(L, creature);
+	LuaScriptInterface::setCreatureMetatable(L, -1, creature);
+	if (attacker) {
+		LuaScriptInterface::pushUserdata(L, attacker);
+		LuaScriptInterface::setCreatureMetatable(L, -1, attacker);
+	}
+	else {
+		lua_pushnil(L);
+	}
+
+	LuaScriptInterface::pushCombatDamage(L, damage);
+
+	if (scriptInterface->protectedCall(L, 7, 4) != 0) {
+		LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
+	}
+	else {
+		damage = LuaScriptInterface::getCombatDamage(L);
+	}
+
+	scriptInterface->resetScriptEnv();
+}
+
 void CreatureEvent::executeExtendedOpcode(Player* player, uint8_t opcode, const std::string& buffer)
 {
 	//onExtendedOpcode(player, opcode, buffer)
diff --git a/src/creatureevent.h b/src/creatureevent.h
index 7617c46..6dbdeac 100644
--- a/src/creatureevent.h
+++ b/src/creatureevent.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -33,6 +33,8 @@ enum CreatureEventType_t {
 	CREATURE_EVENT_DEATH,
 	CREATURE_EVENT_KILL,
 	CREATURE_EVENT_ADVANCE,
+	CREATURE_EVENT_HEALTHCHANGE,
+	CREATURE_EVENT_MANACHANGE,
 	CREATURE_EVENT_EXTENDED_OPCODE, // otclient additional network opcodes
 };
 
@@ -97,6 +99,8 @@ class CreatureEvent final : public Event
 		bool executeOnDeath(Creature* creature, Item* corpse, Creature* killer, Creature* mostDamageKiller, bool lastHitUnjustified, bool mostDamageUnjustified);
 		void executeOnKill(Creature* creature, Creature* target);
 		bool executeAdvance(Player* player, skills_t, uint32_t, uint32_t);
+		void executeHealthChange(Creature* creature, Creature* attacker, CombatDamage& damage);
+		void executeManaChange(Creature* creature, Creature* attacker, CombatDamage& damage);
 		void executeExtendedOpcode(Player* player, uint8_t opcode, const std::string& buffer);
 		//
 
diff --git a/src/cylinder.cpp b/src/cylinder.cpp
index 9e9e289..406ca9a 100644
--- a/src/cylinder.cpp
+++ b/src/cylinder.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/cylinder.h b/src/cylinder.h
index b31765f..872609c 100644
--- a/src/cylinder.h
+++ b/src/cylinder.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/database.cpp b/src/database.cpp
index 5079e08..0dfc590 100644
--- a/src/database.cpp
+++ b/src/database.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/database.h b/src/database.h
index f9ccf57..e0168ba 100644
--- a/src/database.h
+++ b/src/database.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/databasemanager.cpp b/src/databasemanager.cpp
index 07f2325..dc38b37 100644
--- a/src/databasemanager.cpp
+++ b/src/databasemanager.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/databasemanager.h b/src/databasemanager.h
index 4592687..d15f1ec 100644
--- a/src/databasemanager.h
+++ b/src/databasemanager.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/databasetasks.cpp b/src/databasetasks.cpp
index a741e9f..37f1176 100644
--- a/src/databasetasks.cpp
+++ b/src/databasetasks.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/databasetasks.h b/src/databasetasks.h
index 131a173..42b36e2 100644
--- a/src/databasetasks.h
+++ b/src/databasetasks.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/definitions.h b/src/definitions.h
index 2dfc2c6..4ab6c38 100644
--- a/src/definitions.h
+++ b/src/definitions.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,9 +20,9 @@
 #ifndef FS_DEFINITIONS_H_877452FEC245450C9F96B8FD268D8963
 #define FS_DEFINITIONS_H_877452FEC245450C9F96B8FD268D8963
 
-static constexpr auto STATUS_SERVER_NAME = "Nostalrius";
-static constexpr auto STATUS_SERVER_VERSION = "3.0";
-static constexpr auto STATUS_SERVER_DEVELOPERS = "Alejandro Mujica";
+static constexpr auto STATUS_SERVER_NAME = "Sabrehaven";
+static constexpr auto STATUS_SERVER_VERSION = "1.0";
+static constexpr auto STATUS_SERVER_DEVELOPERS = "Sabrehaven Developers Team";
 
 static constexpr auto CLIENT_VERSION_MIN = 772;
 static constexpr auto CLIENT_VERSION_MAX = 772;
@@ -57,7 +57,7 @@ static constexpr auto CLIENT_VERSION_STR = "7.72";
 #pragma warning(disable:4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
 #pragma warning(disable:4351) // new behavior: elements of array will be default initialized
 #pragma warning(disable:4458) // declaration hides class member
-#pragma warning(disable:4018) // signed/unsigned mismatch
+#pragma warning(disable:4996) // inetpton warning
 #endif
 
 #define strcasecmp _stricmp
diff --git a/src/depotlocker.cpp b/src/depotlocker.cpp
index 10f5f15..09189a1 100644
--- a/src/depotlocker.cpp
+++ b/src/depotlocker.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/depotlocker.h b/src/depotlocker.h
index 9d03f8b..094defc 100644
--- a/src/depotlocker.h
+++ b/src/depotlocker.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/enums.h b/src/enums.h
index c4a89d7..1ae3739 100644
--- a/src/enums.h
+++ b/src/enums.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -345,6 +345,11 @@ enum ReturnValue {
 	RETURNVALUE_CANONLYUSEONESHIELD,
 	RETURNVALUE_NOPARTYMEMBERSINRANGE,
 	RETURNVALUE_YOUARENOTTHEOWNER,
+	RETURNVALUE_TRADEPLAYERFARAWAY,
+	RETURNVALUE_YOUDONTOWNTHISHOUSE,
+	RETURNVALUE_TRADEPLAYERALREADYOWNSAHOUSE,
+	RETURNVALUE_TRADEPLAYERHIGHESTBIDDER,
+	RETURNVALUE_YOUCANNOTTRADETHISHOUSE,
 };
 
 struct Outfit_t {
@@ -363,15 +368,26 @@ struct LightInfo {
 	constexpr LightInfo(uint8_t level, uint8_t color) : level(level), color(color) {}
 };
 
+enum CombatOrigin
+{
+	ORIGIN_NONE,
+	ORIGIN_CONDITION,
+	ORIGIN_SPELL,
+	ORIGIN_MELEE,
+	ORIGIN_RANGED,
+};
+
 struct CombatDamage
 {
 	CombatType_t type;
 	int32_t value;
 	int32_t min;
 	int32_t max;
+	CombatOrigin origin;
 
 	CombatDamage()
 	{
+		origin = ORIGIN_NONE;
 		type = COMBAT_NONE;
 		value = 0;
 		min = 0;
diff --git a/src/events.cpp b/src/events.cpp
new file mode 100644
index 0000000..868901e
--- /dev/null
+++ b/src/events.cpp
@@ -0,0 +1,827 @@
+/**
+ * The Forgotten Server - a free and open-source MMORPG server emulator
+ * Copyright (C) 2016  Mark Samman 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "otpch.h"
+
+#include "events.h"
+#include "tools.h"
+#include "item.h"
+#include "player.h"
+
+#include 
+
+Events::Events() :
+	scriptInterface("Event Interface")
+{
+	clear();
+	scriptInterface.initState();
+}
+
+void Events::clear()
+{
+	// Creature
+	creatureOnChangeOutfit = -1;
+	creatureOnAreaCombat = -1;
+	creatureOnTargetCombat = -1;
+
+	// Party
+	partyOnJoin = -1;
+	partyOnLeave = -1;
+	partyOnDisband = -1;
+
+	// Player
+	playerOnLook = -1;
+	playerOnLookInBattleList = -1;
+	playerOnLookInTrade = -1;
+	playerOnMoveItem = -1;
+	playerOnItemMoved = -1;
+	playerOnMoveCreature = -1;
+	playerOnTurn = -1;
+	playerOnTradeRequest = -1;
+	playerOnTradeAccept = -1;
+	playerOnGainExperience = -1;
+	playerOnLoseExperience = -1;
+	playerOnGainSkillTries = -1;
+	playerOnReportBug = -1;
+
+}
+
+bool Events::load()
+{
+	pugi::xml_document doc;
+	pugi::xml_parse_result result = doc.load_file("data/events/events.xml");
+	if (!result) {
+		printXMLError("Error - Events::load", "data/events/events.xml", result);
+		return false;
+	}
+
+	std::set classes;
+	for (auto eventNode : doc.child("events").children()) {
+		if (!eventNode.attribute("enabled").as_bool()) {
+			continue;
+		}
+
+		const std::string& className = eventNode.attribute("class").as_string();
+		auto res = classes.insert(className);
+		if (res.second) {
+			const std::string& lowercase = asLowerCaseString(className);
+			if (scriptInterface.loadFile("data/events/scripts/" + lowercase + ".lua") != 0) {
+				std::cout << "[Warning - Events::load] Can not load script: " << lowercase << ".lua" << std::endl;
+				std::cout << scriptInterface.getLastLuaError() << std::endl;
+			}
+		}
+
+		const std::string& methodName = eventNode.attribute("method").as_string();
+		const int32_t event = scriptInterface.getMetaEvent(className, methodName);
+		if (className == "Creature") {
+			if (methodName == "onChangeOutfit") {
+				creatureOnChangeOutfit = event;
+			}
+			else if (methodName == "onAreaCombat") {
+				creatureOnAreaCombat = event;
+			}
+			else if (methodName == "onTargetCombat") {
+				creatureOnTargetCombat = event;
+			}
+			else {
+				std::cout << "[Warning - Events::load] Unknown creature method: " << methodName << std::endl;
+			}
+		}
+		else if (className == "Party") {
+			if (methodName == "onJoin") {
+				partyOnJoin = event;
+			}
+			else if (methodName == "onLeave") {
+				partyOnLeave = event;
+			}
+			else if (methodName == "onDisband") {
+				partyOnDisband = event;
+			}
+			else if (methodName == "onShareExperience") {
+				partyOnShareExperience = event;
+			}
+			else {
+				std::cout << "[Warning - Events::load] Unknown party method: " << methodName << std::endl;
+			}
+		}
+		else if (className == "Player") {
+			if (methodName == "onLook") {
+				playerOnLook = event;
+			}
+			else if (methodName == "onLookInBattleList") {
+				playerOnLookInBattleList = event;
+			}
+			else if (methodName == "onLookInTrade") {
+				playerOnLookInTrade = event;
+			}
+			else if (methodName == "onTradeRequest") {
+				playerOnTradeRequest = event;
+			}
+			else if (methodName == "onTradeAccept") {
+				playerOnTradeAccept = event;
+			}
+			else if (methodName == "onMoveItem") {
+				playerOnMoveItem = event;
+			}
+			else if (methodName == "onItemMoved") {
+				playerOnItemMoved = event;
+			}
+			else if (methodName == "onMoveCreature") {
+				playerOnMoveCreature = event;
+			}
+			else if (methodName == "onReportBug") {
+				playerOnReportBug = event;
+			}
+			else if (methodName == "onTurn") {
+				playerOnTurn = event;
+			}
+			else if (methodName == "onGainExperience") {
+				playerOnGainExperience = event;
+			}
+			else if (methodName == "onLoseExperience") {
+				playerOnLoseExperience = event;
+			}
+			else if (methodName == "onGainSkillTries") {
+				playerOnGainSkillTries = event;
+			}
+			else {
+				std::cout << "[Warning - Events::load] Unknown player method: " << methodName << std::endl;
+			}
+		}
+		else {
+			std::cout << "[Warning - Events::load] Unknown class: " << className << std::endl;
+		}
+	}
+	return true;
+}
+
+// Creature
+bool Events::eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& outfit)
+{
+	// Creature:onChangeOutfit(outfit) or Creature.onChangeOutfit(self, outfit)
+	if (creatureOnChangeOutfit == -1) {
+		return true;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventCreatureOnChangeOutfit] Call stack overflow" << std::endl;
+		return false;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(creatureOnChangeOutfit, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(creatureOnChangeOutfit);
+
+	LuaScriptInterface::pushUserdata(L, creature);
+	LuaScriptInterface::setCreatureMetatable(L, -1, creature);
+
+	LuaScriptInterface::pushOutfit(L, outfit);
+
+	return scriptInterface.callFunction(2);
+}
+
+ReturnValue Events::eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bool aggressive)
+{
+	// Creature:onAreaCombat(tile, aggressive) or Creature.onAreaCombat(self, tile, aggressive)
+	if (creatureOnAreaCombat == -1) {
+		return RETURNVALUE_NOERROR;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventCreatureOnAreaCombat] Call stack overflow" << std::endl;
+		return RETURNVALUE_NOTPOSSIBLE;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(creatureOnAreaCombat, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(creatureOnAreaCombat);
+
+	if (creature) {
+		LuaScriptInterface::pushUserdata(L, creature);
+		LuaScriptInterface::setCreatureMetatable(L, -1, creature);
+	}
+	else {
+		lua_pushnil(L);
+	}
+
+	LuaScriptInterface::pushUserdata(L, tile);
+	LuaScriptInterface::setMetatable(L, -1, "Tile");
+
+	LuaScriptInterface::pushBoolean(L, aggressive);
+
+	ReturnValue returnValue;
+	if (scriptInterface.protectedCall(L, 3, 1) != 0) {
+		returnValue = RETURNVALUE_NOTPOSSIBLE;
+		LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
+	}
+	else {
+		returnValue = LuaScriptInterface::getNumber(L, -1);
+		lua_pop(L, 1);
+	}
+
+	scriptInterface.resetScriptEnv();
+	return returnValue;
+}
+
+ReturnValue Events::eventCreatureOnTargetCombat(Creature* creature, Creature* target)
+{
+	// Creature:onTargetCombat(target) or Creature.onTargetCombat(self, target)
+	if (creatureOnTargetCombat == -1) {
+		return RETURNVALUE_NOERROR;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventCreatureOnTargetCombat] Call stack overflow" << std::endl;
+		return RETURNVALUE_NOTPOSSIBLE;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(creatureOnTargetCombat, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(creatureOnTargetCombat);
+
+	if (creature) {
+		LuaScriptInterface::pushUserdata(L, creature);
+		LuaScriptInterface::setCreatureMetatable(L, -1, creature);
+	}
+	else {
+		lua_pushnil(L);
+	}
+
+	LuaScriptInterface::pushUserdata(L, target);
+	LuaScriptInterface::setCreatureMetatable(L, -1, target);
+
+	ReturnValue returnValue;
+	if (scriptInterface.protectedCall(L, 2, 1) != 0) {
+		returnValue = RETURNVALUE_NOTPOSSIBLE;
+		LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
+	}
+	else {
+		returnValue = LuaScriptInterface::getNumber(L, -1);
+		lua_pop(L, 1);
+	}
+
+	scriptInterface.resetScriptEnv();
+	return returnValue;
+}
+
+// Party
+bool Events::eventPartyOnJoin(Party* party, Player* player)
+{
+	// Party:onJoin(player) or Party.onJoin(self, player)
+	if (partyOnJoin == -1) {
+		return true;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPartyOnJoin] Call stack overflow" << std::endl;
+		return false;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(partyOnJoin, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(partyOnJoin);
+
+	LuaScriptInterface::pushUserdata(L, party);
+	LuaScriptInterface::setMetatable(L, -1, "Party");
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	return scriptInterface.callFunction(2);
+}
+
+bool Events::eventPartyOnLeave(Party* party, Player* player)
+{
+	// Party:onLeave(player) or Party.onLeave(self, player)
+	if (partyOnLeave == -1) {
+		return true;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPartyOnLeave] Call stack overflow" << std::endl;
+		return false;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(partyOnLeave, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(partyOnLeave);
+
+	LuaScriptInterface::pushUserdata(L, party);
+	LuaScriptInterface::setMetatable(L, -1, "Party");
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	return scriptInterface.callFunction(2);
+}
+
+bool Events::eventPartyOnDisband(Party* party)
+{
+	// Party:onDisband() or Party.onDisband(self)
+	if (partyOnDisband == -1) {
+		return true;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPartyOnDisband] Call stack overflow" << std::endl;
+		return false;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(partyOnDisband, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(partyOnDisband);
+
+	LuaScriptInterface::pushUserdata(L, party);
+	LuaScriptInterface::setMetatable(L, -1, "Party");
+
+	return scriptInterface.callFunction(1);
+}
+
+void Events::eventPartyOnShareExperience(Party* party, uint64_t& exp)
+{
+	// Party:onShareExperience(exp) or Party.onShareExperience(self, exp)
+	if (partyOnShareExperience == -1) {
+		return;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPartyOnShareExperience] Call stack overflow" << std::endl;
+		return;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(partyOnShareExperience, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(partyOnShareExperience);
+
+	LuaScriptInterface::pushUserdata(L, party);
+	LuaScriptInterface::setMetatable(L, -1, "Party");
+
+	lua_pushnumber(L, exp);
+
+	if (scriptInterface.protectedCall(L, 2, 1) != 0) {
+		LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
+	}
+	else {
+		exp = LuaScriptInterface::getNumber(L, -1);
+		lua_pop(L, 1);
+	}
+
+	scriptInterface.resetScriptEnv();
+}
+
+void Events::eventPlayerOnLook(Player* player, const Position& position, Thing* thing, uint8_t stackpos, int32_t lookDistance)
+{
+	// Player:onLook(thing, position, distance) or Player.onLook(self, thing, position, distance)
+	if (playerOnLook == -1) {
+		return;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPlayerOnLook] Call stack overflow" << std::endl;
+		return;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(playerOnLook, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(playerOnLook);
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	if (Creature* creature = thing->getCreature()) {
+		LuaScriptInterface::pushUserdata(L, creature);
+		LuaScriptInterface::setCreatureMetatable(L, -1, creature);
+	}
+	else if (Item* item = thing->getItem()) {
+		LuaScriptInterface::pushUserdata- (L, item);
+		LuaScriptInterface::setItemMetatable(L, -1, item);
+	}
+	else {
+		lua_pushnil(L);
+	}
+
+	LuaScriptInterface::pushPosition(L, position, stackpos);
+	lua_pushnumber(L, lookDistance);
+
+	scriptInterface.callVoidFunction(4);
+}
+
+void Events::eventPlayerOnLookInBattleList(Player* player, Creature* creature, int32_t lookDistance)
+{
+	// Player:onLookInBattleList(creature, position, distance) or Player.onLookInBattleList(self, creature, position, distance)
+	if (playerOnLookInBattleList == -1) {
+		return;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPlayerOnLookInBattleList] Call stack overflow" << std::endl;
+		return;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(playerOnLookInBattleList, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(playerOnLookInBattleList);
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	LuaScriptInterface::pushUserdata(L, creature);
+	LuaScriptInterface::setCreatureMetatable(L, -1, creature);
+
+	lua_pushnumber(L, lookDistance);
+
+	scriptInterface.callVoidFunction(3);
+}
+
+void Events::eventPlayerOnLookInTrade(Player* player, Player* partner, Item* item, int32_t lookDistance)
+{
+	// Player:onLookInTrade(partner, item, distance) or Player.onLookInTrade(self, partner, item, distance)
+	if (playerOnLookInTrade == -1) {
+		return;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPlayerOnLookInTrade] Call stack overflow" << std::endl;
+		return;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(playerOnLookInTrade, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(playerOnLookInTrade);
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	LuaScriptInterface::pushUserdata(L, partner);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	LuaScriptInterface::pushUserdata
- (L, item);
+	LuaScriptInterface::setItemMetatable(L, -1, item);
+
+	lua_pushnumber(L, lookDistance);
+
+	scriptInterface.callVoidFunction(4);
+}
+
+bool Events::eventPlayerOnMoveItem(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder)
+{
+	// Player:onMoveItem(item, count, fromPosition, toPosition) or Player.onMoveItem(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
+	if (playerOnMoveItem == -1) {
+		return true;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPlayerOnMoveItem] Call stack overflow" << std::endl;
+		return false;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(playerOnMoveItem, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(playerOnMoveItem);
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	LuaScriptInterface::pushUserdata
- (L, item);
+	LuaScriptInterface::setItemMetatable(L, -1, item);
+
+	lua_pushnumber(L, count);
+	LuaScriptInterface::pushPosition(L, fromPosition);
+	LuaScriptInterface::pushPosition(L, toPosition);
+
+	LuaScriptInterface::pushCylinder(L, fromCylinder);
+	LuaScriptInterface::pushCylinder(L, toCylinder);
+
+	return scriptInterface.callFunction(7);
+}
+
+void Events::eventPlayerOnItemMoved(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder)
+{
+	// Player:onItemMoved(item, count, fromPosition, toPosition) or Player.onItemMoved(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
+	if (playerOnItemMoved == -1) {
+		return;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPlayerOnItemMoved] Call stack overflow" << std::endl;
+		return;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(playerOnItemMoved, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(playerOnItemMoved);
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	LuaScriptInterface::pushUserdata
- (L, item);
+	LuaScriptInterface::setItemMetatable(L, -1, item);
+
+	lua_pushnumber(L, count);
+	LuaScriptInterface::pushPosition(L, fromPosition);
+	LuaScriptInterface::pushPosition(L, toPosition);
+
+	LuaScriptInterface::pushCylinder(L, fromCylinder);
+	LuaScriptInterface::pushCylinder(L, toCylinder);
+
+	scriptInterface.callVoidFunction(7);
+}
+
+bool Events::eventPlayerOnMoveCreature(Player* player, Creature* creature, const Position& fromPosition, const Position& toPosition)
+{
+	// Player:onMoveCreature(creature, fromPosition, toPosition) or Player.onMoveCreature(self, creature, fromPosition, toPosition)
+	if (playerOnMoveCreature == -1) {
+		return true;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPlayerOnMoveCreature] Call stack overflow" << std::endl;
+		return false;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(playerOnMoveCreature, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(playerOnMoveCreature);
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	LuaScriptInterface::pushUserdata(L, creature);
+	LuaScriptInterface::setCreatureMetatable(L, -1, creature);
+
+	LuaScriptInterface::pushPosition(L, fromPosition);
+	LuaScriptInterface::pushPosition(L, toPosition);
+
+	return scriptInterface.callFunction(4);
+}
+
+bool Events::eventPlayerOnReportBug(Player* player, const std::string& message, const Position& position)
+{
+	// Player:onReportBug(message, position, category)
+	if (playerOnReportBug == -1) {
+		return true;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPlayerOnReportBug] Call stack overflow" << std::endl;
+		return false;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(playerOnReportBug, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(playerOnReportBug);
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	LuaScriptInterface::pushString(L, message);
+	LuaScriptInterface::pushPosition(L, position);
+
+	return scriptInterface.callFunction(3);
+}
+
+bool Events::eventPlayerOnTurn(Player* player, Direction direction)
+{
+	// Player:onTurn(direction) or Player.onTurn(self, direction)
+	if (playerOnTurn == -1) {
+		return true;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPlayerOnTurn] Call stack overflow" << std::endl;
+		return false;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(playerOnTurn, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(playerOnTurn);
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	lua_pushnumber(L, direction);
+
+	return scriptInterface.callFunction(2);
+}
+
+bool Events::eventPlayerOnTradeRequest(Player* player, Player* target, Item* item)
+{
+	// Player:onTradeRequest(target, item)
+	if (playerOnTradeRequest == -1) {
+		return true;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPlayerOnTradeRequest] Call stack overflow" << std::endl;
+		return false;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(playerOnTradeRequest, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(playerOnTradeRequest);
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	LuaScriptInterface::pushUserdata(L, target);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	LuaScriptInterface::pushUserdata
- (L, item);
+	LuaScriptInterface::setItemMetatable(L, -1, item);
+
+	return scriptInterface.callFunction(3);
+}
+
+bool Events::eventPlayerOnTradeAccept(Player* player, Player* target, Item* item, Item* targetItem)
+{
+	// Player:onTradeAccept(target, item, targetItem)
+	if (playerOnTradeAccept == -1) {
+		return true;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPlayerOnTradeAccept] Call stack overflow" << std::endl;
+		return false;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(playerOnTradeAccept, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(playerOnTradeAccept);
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	LuaScriptInterface::pushUserdata(L, target);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	LuaScriptInterface::pushUserdata
- (L, item);
+	LuaScriptInterface::setItemMetatable(L, -1, item);
+
+	LuaScriptInterface::pushUserdata
- (L, targetItem);
+	LuaScriptInterface::setItemMetatable(L, -1, targetItem);
+
+	return scriptInterface.callFunction(4);
+}
+
+void Events::eventPlayerOnGainExperience(Player* player, Creature* source, uint64_t& exp, uint64_t rawExp)
+{
+	// Player:onGainExperience(source, exp, rawExp)
+	// rawExp gives the original exp which is not multiplied
+	if (playerOnGainExperience == -1) {
+		return;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPlayerOnGainExperience] Call stack overflow" << std::endl;
+		return;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(playerOnGainExperience, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(playerOnGainExperience);
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	if (source) {
+		LuaScriptInterface::pushUserdata(L, source);
+		LuaScriptInterface::setCreatureMetatable(L, -1, source);
+	}
+	else {
+		lua_pushnil(L);
+	}
+
+	lua_pushnumber(L, exp);
+	lua_pushnumber(L, rawExp);
+
+	if (scriptInterface.protectedCall(L, 4, 1) != 0) {
+		LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
+	}
+	else {
+		exp = LuaScriptInterface::getNumber(L, -1);
+		lua_pop(L, 1);
+	}
+
+	scriptInterface.resetScriptEnv();
+}
+
+void Events::eventPlayerOnLoseExperience(Player* player, uint64_t& exp)
+{
+	// Player:onLoseExperience(exp)
+	if (playerOnLoseExperience == -1) {
+		return;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPlayerOnLoseExperience] Call stack overflow" << std::endl;
+		return;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(playerOnLoseExperience, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(playerOnLoseExperience);
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	lua_pushnumber(L, exp);
+
+	if (scriptInterface.protectedCall(L, 2, 1) != 0) {
+		LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
+	}
+	else {
+		exp = LuaScriptInterface::getNumber(L, -1);
+		lua_pop(L, 1);
+	}
+
+	scriptInterface.resetScriptEnv();
+}
+
+void Events::eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_t& tries)
+{
+	// Player:onGainSkillTries(skill, tries)
+	if (playerOnGainSkillTries == -1) {
+		return;
+	}
+
+	if (!scriptInterface.reserveScriptEnv()) {
+		std::cout << "[Error - Events::eventPlayerOnGainSkillTries] Call stack overflow" << std::endl;
+		return;
+	}
+
+	ScriptEnvironment* env = scriptInterface.getScriptEnv();
+	env->setScriptId(playerOnGainSkillTries, &scriptInterface);
+
+	lua_State* L = scriptInterface.getLuaState();
+	scriptInterface.pushFunction(playerOnGainSkillTries);
+
+	LuaScriptInterface::pushUserdata(L, player);
+	LuaScriptInterface::setMetatable(L, -1, "Player");
+
+	lua_pushnumber(L, skill);
+	lua_pushnumber(L, tries);
+
+	if (scriptInterface.protectedCall(L, 3, 1) != 0) {
+		LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
+	}
+	else {
+		tries = LuaScriptInterface::getNumber(L, -1);
+		lua_pop(L, 1);
+	}
+
+	scriptInterface.resetScriptEnv();
+}
\ No newline at end of file
diff --git a/src/events.h b/src/events.h
new file mode 100644
index 0000000..7582c29
--- /dev/null
+++ b/src/events.h
@@ -0,0 +1,95 @@
+/**
+ * The Forgotten Server - a free and open-source MMORPG server emulator
+ * Copyright (C) 2016  Mark Samman 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FS_EVENTS_H_BD444CC0EE167E5777E4C90C766B36DC
+#define FS_EVENTS_H_BD444CC0EE167E5777E4C90C766B36DC
+
+#include "luascript.h"
+
+class Party;
+class ItemType;
+class Tile;
+
+class Events
+{
+public:
+	Events();
+
+	void clear();
+	bool load();
+
+	// Creature
+	bool eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& outfit);
+	ReturnValue eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bool aggressive);
+	ReturnValue eventCreatureOnTargetCombat(Creature* creature, Creature* target);
+
+	// Party
+	bool eventPartyOnJoin(Party* party, Player* player);
+	bool eventPartyOnLeave(Party* party, Player* player);
+	bool eventPartyOnDisband(Party* party);
+	void eventPartyOnShareExperience(Party* party, uint64_t& exp);
+
+	// Player
+	void eventPlayerOnLook(Player* player, const Position& position, Thing* thing, uint8_t stackpos, int32_t lookDistance);
+	void eventPlayerOnLookInBattleList(Player* player, Creature* creature, int32_t lookDistance);
+	void eventPlayerOnLookInTrade(Player* player, Player* partner, Item* item, int32_t lookDistance);
+	bool eventPlayerOnMoveItem(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder);
+	void eventPlayerOnItemMoved(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder);
+	bool eventPlayerOnMoveCreature(Player* player, Creature* creature, const Position& fromPosition, const Position& toPosition);
+	void eventPlayerOnReportRuleViolation(Player* player, const std::string& targetName, uint8_t reportType, uint8_t reportReason, const std::string& comment, const std::string& translation);
+	bool eventPlayerOnReportBug(Player* player, const std::string& message, const Position& position);
+	bool eventPlayerOnTurn(Player* player, Direction direction);
+	bool eventPlayerOnTradeRequest(Player* player, Player* target, Item* item);
+	bool eventPlayerOnTradeAccept(Player* player, Player* target, Item* item, Item* targetItem);
+	void eventPlayerOnGainExperience(Player* player, Creature* source, uint64_t& exp, uint64_t rawExp);
+	void eventPlayerOnLoseExperience(Player* player, uint64_t& exp);
+	void eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_t& tries);
+
+private:
+	LuaScriptInterface scriptInterface;
+
+	// Creature
+	int32_t creatureOnChangeOutfit;
+	int32_t creatureOnAreaCombat;
+	int32_t creatureOnTargetCombat;
+
+	// Party
+	int32_t partyOnJoin;
+	int32_t partyOnLeave;
+	int32_t partyOnDisband;
+	int32_t partyOnShareExperience;
+
+	// Player
+	int32_t playerOnLook;
+	int32_t playerOnLookInBattleList;
+	int32_t playerOnLookInTrade;
+	int32_t playerOnMoveItem;
+	int32_t playerOnItemMoved;
+	int32_t playerOnMoveCreature;
+	int32_t playerOnReportRuleViolation;
+	int32_t playerOnReportBug;
+	int32_t playerOnTurn;
+	int32_t playerOnTradeRequest;
+	int32_t playerOnTradeAccept;
+	int32_t playerOnGainExperience;
+	int32_t playerOnLoseExperience;
+	int32_t playerOnGainSkillTries;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/fileloader.cpp b/src/fileloader.cpp
index d37955f..be25ecf 100644
--- a/src/fileloader.cpp
+++ b/src/fileloader.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/fileloader.h b/src/fileloader.h
index 5ce9c5b..74872b0 100644
--- a/src/fileloader.h
+++ b/src/fileloader.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/game.cpp b/src/game.cpp
index 1c6d3d6..1d587b6 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,9 +22,9 @@
 #include "pugicast.h"
 
 #include "items.h"
-#include "commands.h"
 #include "creature.h"
 #include "monster.h"
+#include "events.h"
 #include "game.h"
 #include "actions.h"
 #include "iologindata.h"
@@ -36,6 +36,7 @@
 #include "bed.h"
 #include "scheduler.h"
 #include "databasetasks.h"
+#include "movement.h"
 
 extern ConfigManager g_config;
 extern Actions* g_actions;
@@ -44,6 +45,10 @@ extern TalkActions* g_talkActions;
 extern Spells* g_spells;
 extern Vocations g_vocations;
 extern GlobalEvents* g_globalEvents;
+extern Events* g_events;
+extern CreatureEvents* g_creatureEvents;
+extern Monsters g_monsters;
+extern MoveEvents* g_moveEvents;
 
 Game::~Game()
 {
@@ -84,8 +89,6 @@ void Game::setGameState(GameState_t newState)
 	gameState = newState;
 	switch (newState) {
 		case GAME_STATE_INIT: {
-			commands.loadFromXml();
-
 			loadExperienceStages();
 
 			groups.load();
@@ -219,7 +222,7 @@ Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index
 			}
 
 			case STACKPOS_USEITEM: {
-				thing = tile->getUseItem();
+				thing = tile->getUseItem(index);
 				break;
 			}
 
@@ -231,7 +234,7 @@ Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index
 			case STACKPOS_USETARGET: {
 				thing = tile->getTopCreature();
 				if (!thing) {
-					thing = tile->getUseItem();
+					thing = tile->getUseItem(index);
 				}
 				break;
 			}
@@ -651,6 +654,13 @@ void Game::playerMoveCreature(Player* player, Creature* movingCreature, const Po
 
 	player->setNextActionTask(nullptr);
 
+	if (g_config.getBoolean(ConfigManager::BLOCK_HEIGHT)) {
+		if (toTile->getHeight() > 1) {
+			player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
+			return;
+		}
+	}
+
 	if (!Position::areInRange<1, 1, 0>(movingCreatureOrigPos, player->getPosition())) {
 		//need to walk to the creature first before moving it
 		std::forward_list listDir;
@@ -705,6 +715,10 @@ void Game::playerMoveCreature(Player* player, Creature* movingCreature, const Po
 		}
 	}
 
+	if (!g_events->eventPlayerOnMoveCreature(player, movingCreature, movingCreaturePos, toPos)) {
+		return;
+	}
+
 	ReturnValue ret = internalMoveCreature(*movingCreature, *toTile);
 	if (ret != RETURNVALUE_NOERROR) {
 		player->sendCancelMessage(ret);
@@ -729,7 +743,8 @@ ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction,
 					internalCreatureTurn(creature, DIRECTION_NORTH);
 				}
 			}
-		} else {
+		}
+		else {
 			//try go down
 			Tile* tmpTile = map.getTile(destPos.x, destPos.y, destPos.z);
 			if (currentPos.z != 7 && (tmpTile == nullptr || (tmpTile->getGround() == nullptr && !tmpTile->hasFlag(TILESTATE_BLOCKSOLID)))) {
@@ -742,11 +757,37 @@ ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction,
 		}
 	}
 
+	ReturnValue ret = RETURNVALUE_NOTPOSSIBLE;
 	Tile* toTile = map.getTile(destPos);
-	if (!toTile) {
-		return RETURNVALUE_NOTPOSSIBLE;
+
+	Tile* toPos = map.getTile(destPos.x, destPos.y, destPos.z);
+	Tile* fromPos = map.getTile(currentPos.x, currentPos.y, currentPos.z);
+
+	if (g_config.getBoolean(ConfigManager::BLOCK_HEIGHT)) {
+		if (toTile) {
+			if (currentPos.z > destPos.z && toPos->getHeight() > 1);
+			// not possible
+			else if ((((toPos->getHeight() - fromPos->getHeight()) < 2)) ||
+				(fromPos->hasHeight(3) && (currentPos.z == destPos.z)) ||
+				((currentPos.z < destPos.z) && (toPos->hasHeight(3) && (fromPos->getHeight() < 2))))
+				ret = internalMoveCreature(*creature, *toTile, flags);
+		}
+
+		if (ret != RETURNVALUE_NOERROR) {
+			if (Player* player = creature->getPlayer()) {
+				player->sendCancelMessage(ret);
+				player->sendCancelWalk();
+			}
+		}
+
+		return ret;
+	}
+	else {
+		if (!toTile) {
+			return RETURNVALUE_NOTPOSSIBLE;
+		}
+		return internalMoveCreature(*creature, *toTile, flags);
 	}
-	return internalMoveCreature(*creature, *toTile, flags);
 }
 
 ReturnValue Game::internalMoveCreature(Creature& creature, Tile& toTile, uint32_t flags /*= 0*/)
@@ -964,6 +1005,10 @@ void Game::playerMoveItem(Player* player, const Position& fromPos,
 		return;
 	}
 
+	if (!g_events->eventPlayerOnMoveItem(player, item, count, fromPos, toPos, fromCylinder, toCylinder)) {
+		return;
+	}
+
 	uint8_t toIndex = 0;
 	if (toPos.x == 0xFFFF) {
 		if (toPos.y & 0x40) {
@@ -976,6 +1021,8 @@ void Game::playerMoveItem(Player* player, const Position& fromPos,
 	ReturnValue ret = internalMoveItem(fromCylinder, toCylinder, toIndex, item, count, nullptr, 0, player);
 	if (ret != RETURNVALUE_NOERROR) {
 		player->sendCancelMessage(ret);
+	} else {
+		g_events->eventPlayerOnItemMoved(player, item, count, fromPos, toPos, fromCylinder, toCylinder);
 	}
 }
 
@@ -2316,6 +2363,10 @@ void Game::playerRequestTrade(uint32_t playerId, const Position& pos, uint8_t st
 		return;
 	}
 
+	if (!g_events->eventPlayerOnTradeRequest(player, tradePartner, tradeItem)) {
+		return;
+	}
+
 	internalStartTrade(player, tradePartner, tradeItem);
 }
 
@@ -2379,6 +2430,11 @@ void Game::playerAcceptTrade(uint32_t playerId)
 		Item* tradeItem1 = player->tradeItem;
 		Item* tradeItem2 = tradePartner->tradeItem;
 
+		if (!g_events->eventPlayerOnTradeAccept(player, tradePartner, tradeItem1, tradeItem2)) {
+			internalCloseTrade(player);
+			return;
+		}
+
 		player->setTradeState(TRADE_TRANSFER);
 		tradePartner->setTradeState(TRADE_TRANSFER);
 
@@ -2508,10 +2564,8 @@ void Game::playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, uint8_t
 	int32_t lookDistance = std::max(Position::getDistanceX(playerPosition, tradeItemPosition),
 	                                         Position::getDistanceY(playerPosition, tradeItemPosition));
 
-	std::stringstream ss;
 	if (index == 0) {
-		ss << "You see " << tradeItem->getDescription(lookDistance);
-		player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
+		g_events->eventPlayerOnLookInTrade(player, tradePartner, tradeItem, lookDistance);
 		return;
 	}
 
@@ -2531,8 +2585,7 @@ void Game::playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, uint8_t
 			}
 
 			if (--index == 0) {
-				ss << "You see " << item->getDescription(lookDistance);
-				player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
+				g_events->eventPlayerOnLookInTrade(player, tradePartner, item, lookDistance);
 				return;
 			}
 		}
@@ -2624,52 +2677,7 @@ void Game::playerLookAt(uint32_t playerId, const Position& pos, uint8_t stackPos
 		lookDistance = -1;
 	}
 
-	std::ostringstream ss;
-	ss << "You see " << thing->getDescription(lookDistance);
-
-	if (player->isAccessPlayer()) {
-		Item* item = thing->getItem();
-		if (item) {
-			ss << std::endl << "ItemID: [" << item->getID() << ']';
-
-			uint16_t actionId = item->getActionId();
-			if (actionId != 0) {
-				ss << ", ActionID: [" << actionId << ']';
-			}
-
-			uint16_t movementID = item->getMovementId();
-			if (movementID != 0) {
-				ss << ", MovementID: [" << movementID << ']';
-			}
-
-			ss << '.';
-			const ItemType& it = Item::items[item->getID()];
-
-			if (it.transformEquipTo) {
-				ss << std::endl << "TransformTo: [" << it.transformEquipTo << "] (onEquip).";
-			} else if (it.transformDeEquipTo) {
-				ss << std::endl << "TransformTo: [" << it.transformDeEquipTo << "] (onDeEquip).";
-			}
-
-			if (it.decayTo != -1) {
-				ss << std::endl << "DecayTo: [" << it.decayTo << "].";
-			}
-		}
-
-		if (const Creature* creature = thing->getCreature()) {
-			ss << std::endl << "Health: [" << creature->getHealth() << " / " << creature->getMaxHealth() << ']';
-
-			if (creature->getMaxMana() > 0) {
-				ss << ", Mana: [" << creature->getMana() << " / " << creature->getMaxMana() << ']';
-			}
-
-			ss << '.';
-		}
-
-		ss << std::endl << "Position: [X: " << thingPos.x << "] [Y: " << thingPos.y << "] [Z: " << thingPos.getZ() << "].";
-	}
-
-	player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
+	g_events->eventPlayerOnLook(player, pos, thing, stackPos, lookDistance);
 }
 
 void Game::playerLookInBattleList(uint32_t playerId, uint32_t creatureId)
@@ -2704,21 +2712,7 @@ void Game::playerLookInBattleList(uint32_t playerId, uint32_t creatureId)
 		lookDistance = -1;
 	}
 
-	std::ostringstream ss;
-	ss << "You see " << creature->getDescription(lookDistance);
-
-	if (player->isAccessPlayer()) {
-		ss << std::endl << "Health: [" << creature->getHealth() << " / " << creature->getMaxHealth() << ']';
-
-		if (creature->getMaxMana() > 0) {
-			ss << ", Mana: [" << creature->getMana() << " / " << creature->getMaxMana() << ']';
-		}
-
-		ss << '.' << std::endl;
-		ss << "Position: [X: " << creaturePos.x << "] [Y: " << creaturePos.y << "] [Z: " << creaturePos.getZ() << "].";
-	}
-
-	player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
+	g_events->eventPlayerOnLookInBattleList(player, creature, lookDistance);
 }
 
 void Game::playerCancelAttackAndFollow(uint32_t playerId)
@@ -2847,6 +2841,10 @@ void Game::playerTurn(uint32_t playerId, Direction dir)
 		return;
 	}
 
+	if (!g_events->eventPlayerOnTurn(player, dir)) {
+		return;
+	}
+
 	player->resetIdleTime();
 	internalCreatureTurn(player, dir);
 }
@@ -2897,6 +2895,10 @@ void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
 
 	player->resetIdleTime();
 
+	if (playerSaySpell(player, type, text)) {
+		return;
+	}
+
 	uint32_t muteTime = player->isMuted();
 	if (muteTime > 0) {
 		std::ostringstream ss;
@@ -2905,14 +2907,6 @@ void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
 		return;
 	}
 
-	if (playerSayCommand(player, text)) {
-		return;
-	}
-
-	if (playerSaySpell(player, type, text)) {
-		return;
-	}
-
 	if (!text.empty() && text.front() == '/' && player->isAccessPlayer()) {
 		return;
 	}
@@ -2966,23 +2960,6 @@ void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
 	}
 }
 
-bool Game::playerSayCommand(Player* player, const std::string& text)
-{
-	if (text.empty()) {
-		return false;
-	}
-
-	char firstCharacter = text.front();
-	for (char commandTag : commandTags) {
-		if (commandTag == firstCharacter) {
-			if (commands.exeCommand(*player, text)) {
-				return true;
-			}
-		}
-	}
-	return false;
-}
-
 bool Game::playerSaySpell(Player* player, SpeakClasses type, const std::string& text)
 {
 	std::string words = text;
@@ -3234,6 +3211,10 @@ void Game::changeSpeed(Creature* creature, int32_t varSpeedDelta)
 
 void Game::internalCreatureChangeOutfit(Creature* creature, const Outfit_t& outfit)
 {
+	if (!g_events->eventCreatureOnChangeOutfit(creature, outfit)) {
+		return;
+	}
+
 	creature->setCurrentOutfit(outfit);
 
 	if (creature->isInvisible()) {
@@ -3403,6 +3384,17 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
 			return false;
 		}
 
+		if (damage.origin != ORIGIN_NONE) {
+			const auto& events = target->getCreatureEvents(CREATURE_EVENT_HEALTHCHANGE);
+			if (!events.empty()) {
+				for (CreatureEvent* creatureEvent : events) {
+					creatureEvent->executeHealthChange(target, attacker, damage);
+				}
+				damage.origin = ORIGIN_NONE;
+				return combatChangeHealth(attacker, target, damage);
+			}
+		}
+
 		int32_t realHealthChange = target->getHealth();
 		target->gainHealth(attacker, damage.value);
 		realHealthChange = target->getHealth() - realHealthChange;
@@ -3410,7 +3402,8 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
 		if (realHealthChange > 0 && !target->isInGhostMode()) {
 			addMagicEffect(targetPos, CONST_ME_MAGIC_BLUE);
 		}
-	} else {
+	}
+	else {
 		if (Monster* monster = target->getMonster()) {
 			// makes monsters aggressive when damaged
 			// basically stands for UNDERATTACK stance under CipSoft servers
@@ -3431,7 +3424,8 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
 		Player* attackerPlayer;
 		if (attacker) {
 			attackerPlayer = attacker->getPlayer();
-		} else {
+		}
+		else {
 			attackerPlayer = nullptr;
 		}
 		damage.value = std::abs(damage.value);
@@ -3440,25 +3434,39 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
 		if (healthChange == 0) {
 			return true;
 		}
-
+		Player* targetPlayer = target->getPlayer();
 		SpectatorVec list;
 		if (target->hasCondition(CONDITION_MANASHIELD) && damage.type != COMBAT_UNDEFINEDDAMAGE) {
-			int32_t manaDamage = std::min(target->getMana(), healthChange);
+			int32_t manaDamage = std::min(targetPlayer->getMana(), healthChange);
 			if (manaDamage != 0) {
-				target->drainMana(attacker, manaDamage);
+				if (damage.origin != ORIGIN_NONE) {
+					const auto& events = target->getCreatureEvents(CREATURE_EVENT_MANACHANGE);
+					if (!events.empty()) {
+						for (CreatureEvent* creatureEvent : events) {
+							creatureEvent->executeManaChange(target, attacker, damage);
+						}
+						healthChange = damage.value;
+						if (healthChange == 0) {
+							return true;
+						}
+						manaDamage = std::min(targetPlayer->getMana(), healthChange);
+					}
+				}
+				targetPlayer->drainMana(attacker, manaDamage);
 				map.getSpectators(list, targetPos, true, true);
 				addMagicEffect(list, targetPos, CONST_ME_LOSEENERGY);
 
 				std::string damageString = std::to_string(manaDamage);
 
-				Player* targetPlayer = target->getPlayer();
 				if (targetPlayer) {
 					std::stringstream ss;
 					if (!attacker) {
 						ss << "You lose " << damageString << " mana.";
-					} else if (targetPlayer == attackerPlayer) {
+					}
+					else if (targetPlayer == attackerPlayer) {
 						ss << "You lose " << damageString << " mana due to your own attack.";
-					} else {
+					}
+					else {
 						ss << "You lose " << damageString << " mana due to an attack by " << attacker->getNameDescription() << '.';
 					}
 					targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
@@ -3489,19 +3497,11 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
 		realDamage = damage.value;
 		if (realDamage == 0) {
 			return true;
-		} else if (realDamage >= targetHealth) {
-			for (CreatureEvent* creatureEvent : target->getCreatureEvents(CREATURE_EVENT_PREPAREDEATH)) {
-				if (!creatureEvent->executeOnPrepareDeath(target, attacker)) {
-					return false;
-				}
-			}
 		}
 
-		target->drainHealth(attacker, realDamage);
 		if (list.empty()) {
 			map.getSpectators(list, targetPos, true, true);
 		}
-		addCreatureHealth(list, target);
 
 		TextColor_t color = TEXTCOLOR_NONE;
 		uint8_t hitEffect;
@@ -3514,15 +3514,15 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
 
 		if (color != TEXTCOLOR_NONE) {
 			std::string damageString = std::to_string(realDamage) + (realDamage != 1 ? " hitpoints" : " hitpoint");
-
-			Player* targetPlayer = target->getPlayer();
 			if (targetPlayer) {
 				std::stringstream ss;
 				if (!attacker) {
 					ss << "You lose " << damageString << ".";
-				} else if (targetPlayer == attackerPlayer) {
+				}
+				else if (targetPlayer == attackerPlayer) {
 					ss << "You lose " << damageString << " due to your own attack.";
-				} else {
+				}
+				else {
 					ss << "You lose " << damageString << " due to an attack by " << attacker->getNameDescription() << '.';
 				}
 				targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
@@ -3534,16 +3534,43 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
 				tmpPlayer->sendAnimatedText(targetPos, color, realDamageStr);
 			}
 		}
+
+		if (realDamage >= targetHealth) {
+			for (CreatureEvent* creatureEvent : target->getCreatureEvents(CREATURE_EVENT_PREPAREDEATH)) {
+				if (!creatureEvent->executeOnPrepareDeath(target, attacker)) {
+					return false;
+				}
+			}
+		}
+
+		target->drainHealth(attacker, realDamage);
+		addCreatureHealth(list, target);
 	}
 
 	return true;
 }
 
-bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaChange)
+bool Game::combatChangeMana(Creature* attacker, Creature* target, CombatDamage& damage)
 {
+	Player* targetPlayer = target->getPlayer();
+	if (!targetPlayer) {
+		return true;
+	}
+	int32_t manaChange = damage.value;
 	if (manaChange > 0) {
-		target->changeMana(manaChange);
-	} else {
+		if (damage.origin != ORIGIN_NONE) {
+			const auto& events = target->getCreatureEvents(CREATURE_EVENT_MANACHANGE);
+			if (!events.empty()) {
+				for (CreatureEvent* creatureEvent : events) {
+					creatureEvent->executeManaChange(target, attacker, damage);
+				}
+				damage.origin = ORIGIN_NONE;
+				return combatChangeMana(attacker, target, damage);
+			}
+		}
+		targetPlayer->changeMana(manaChange);
+	}
+	else {
 		const Position& targetPos = target->getPosition();
 		if (!target->isAttackable()) {
 			if (!target->isInGhostMode()) {
@@ -3555,11 +3582,12 @@ bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaCh
 		Player* attackerPlayer;
 		if (attacker) {
 			attackerPlayer = attacker->getPlayer();
-		} else {
+		}
+		else {
 			attackerPlayer = nullptr;
 		}
 
-		int32_t manaLoss = std::min(target->getMana(), -manaChange);
+		int32_t manaLoss = std::min(targetPlayer->getMana(), -manaChange);
 		BlockType_t blockType = target->blockHit(attacker, COMBAT_MANADRAIN, manaLoss);
 		if (blockType != BLOCK_NONE) {
 			addMagicEffect(targetPos, CONST_ME_POFF);
@@ -3570,11 +3598,20 @@ bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaCh
 			return true;
 		}
 
-		target->drainMana(attacker, manaLoss);
+		if (damage.origin != ORIGIN_NONE) {
+			const auto& events = target->getCreatureEvents(CREATURE_EVENT_MANACHANGE);
+			if (!events.empty()) {
+				for (CreatureEvent* creatureEvent : events) {
+					creatureEvent->executeManaChange(target, attacker, damage);
+				}
+				damage.origin = ORIGIN_NONE;
+				return combatChangeMana(attacker, target, damage);
+			}
+		}
+
+		targetPlayer->drainMana(attacker, manaLoss);
 
 		std::string damageString = std::to_string(manaLoss);
-	
-		Player* targetPlayer = target->getPlayer();
 
 		SpectatorVec list;
 		map.getSpectators(list, targetPos, false, true);
@@ -3582,9 +3619,11 @@ bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaCh
 			std::stringstream ss;
 			if (!attacker) {
 				ss << "You lose " << damageString << " mana.";
-			} else if (targetPlayer == attackerPlayer) {
+			}
+			else if (targetPlayer == attackerPlayer) {
 				ss << "You lose " << damageString << " mana due to your own attack.";
-			} else {
+			}
+			else {
 				ss << "You lose " << damageString << " mana due to an attack by " << attacker->getNameDescription() << '.';
 			}
 			targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
@@ -3814,23 +3853,9 @@ void Game::getWorldLightInfo(LightInfo& lightInfo) const
 	lightInfo.color = 0xD7;
 }
 
-void Game::addCommandTag(char tag)
-{
-	for (char commandTag : commandTags) {
-		if (commandTag == tag) {
-			return;
-		}
-	}
-	commandTags.push_back(tag);
-}
-
-void Game::resetCommandTag()
-{
-	commandTags.clear();
-}
-
 void Game::shutdown()
 {
+	saveGameState();
 	std::cout << "Shutting down..." << std::flush;
 
 	g_scheduler.shutdown();
@@ -4324,22 +4349,8 @@ void Game::playerReportBug(uint32_t playerId, const std::string& message)
 		return;
 	}
 
-	if (player->getAccountType() == ACCOUNT_TYPE_NORMAL) {
-		return;
-	}
-
-	std::string fileName = "data/reports/" + player->getName() + " report.txt";
-	FILE* file = fopen(fileName.c_str(), "a");
-	if (!file) {
-		player->sendTextMessage(MESSAGE_EVENT_DEFAULT, "There was an error when processing your report, please contact a gamemaster.");
-		return;
-	}
-
-	const Position& playerPosition = player->getPosition();
-	fprintf(file, "------------------------------\nName: %s [Player Position: %u, %u, %u]\nComment: %s\n", player->getName().c_str(), playerPosition.x, playerPosition.y, playerPosition.z, message.c_str());
-	fclose(file);
-
-	player->sendTextMessage(MESSAGE_EVENT_DEFAULT, "Your report has been sent to " + g_config.getString(ConfigManager::SERVER_NAME) + ".");
+	const Position& position = player->getPosition();
+	g_events->eventPlayerOnReportBug(player, message, position);
 }
 
 void Game::playerDebugAssert(uint32_t playerId, const std::string& assertLine, const std::string& date, const std::string& description, const std::string& comment)
@@ -4534,3 +4545,64 @@ void Game::removeBedSleeper(uint32_t guid)
 		bedSleepersMap.erase(it);
 	}
 }
+
+bool Game::reload(ReloadTypes_t reloadType)
+{
+	switch (reloadType) {
+	case RELOAD_TYPE_ACTIONS: return g_actions->reload();
+	case RELOAD_TYPE_CHAT: return g_chat->load();
+	case RELOAD_TYPE_CONFIG: return g_config.reload();
+	case RELOAD_TYPE_CREATURESCRIPTS: return g_creatureEvents->reload();
+	case RELOAD_TYPE_EVENTS: return g_events->load();
+	case RELOAD_TYPE_GLOBALEVENTS: return g_globalEvents->reload();
+	case RELOAD_TYPE_ITEMS: return Item::items.reload();
+	case RELOAD_TYPE_MONSTERS: return g_monsters.reload();
+	case RELOAD_TYPE_MOVEMENTS: return g_moveEvents->reload();
+	case RELOAD_TYPE_NPCS: {
+		Npcs::reload();
+		return true;
+	}
+	case RELOAD_TYPE_RAIDS: return raids.reload() && raids.startup();
+
+	case RELOAD_TYPE_SPELLS: {
+		if (!g_spells->reload()) {
+			std::cout << "[Error - Game::reload] Failed to reload spells." << std::endl;
+			std::terminate();
+		}
+		else if (!g_monsters.reload()) {
+			std::cout << "[Error - Game::reload] Failed to reload monsters." << std::endl;
+			std::terminate();
+		}
+		return true;
+	}
+
+	case RELOAD_TYPE_TALKACTIONS: return g_talkActions->reload();
+
+	default: {
+		if (!g_spells->reload()) {
+			std::cout << "[Error - Game::reload] Failed to reload spells." << std::endl;
+			std::terminate();
+			return false;
+		}
+		else if (!g_monsters.reload()) {
+			std::cout << "[Error - Game::reload] Failed to reload monsters." << std::endl;
+			std::terminate();
+			return false;
+		}
+
+		g_actions->reload();
+		g_config.reload();
+		g_creatureEvents->reload();
+		g_monsters.reload();
+		g_moveEvents->reload();
+		Npcs::reload();
+		raids.reload() && raids.startup();
+		g_talkActions->reload();
+		Item::items.reload();
+		g_globalEvents->reload();
+		g_events->load();
+		g_chat->load();
+		return true;
+	}
+	}
+}
diff --git a/src/game.h b/src/game.h
index 20d80e2..a484818 100644
--- a/src/game.h
+++ b/src/game.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@
 
 #include "account.h"
 #include "combat.h"
-#include "commands.h"
 #include "groups.h"
 #include "map.h"
 #include "position.h"
@@ -436,7 +435,7 @@ class Game
 		void combatGetTypeInfo(CombatType_t combatType, Creature* target, TextColor_t& color, uint8_t& effect);
 
 		bool combatChangeHealth(Creature* attacker, Creature* target, CombatDamage& damage);
-		bool combatChangeMana(Creature* attacker, Creature* target, int32_t manaChange);
+		bool combatChangeMana(Creature* attacker, Creature* target, CombatDamage& damage);
 
 		//animation help functions
 		void addCreatureHealth(const Creature* target);
@@ -449,9 +448,6 @@ class Game
 		static void addAnimatedText(const SpectatorVec& list, const Position& pos, uint8_t color, const std::string& text);
 		void addMonsterSayText(const Position& pos, const std::string& text);
 
-		void addCommandTag(char tag);
-		void resetCommandTag();
-
 		void startDecay(Item* item);
 		int32_t getLightHour() const {
 			return lightHour;
@@ -488,13 +484,13 @@ class Game
 		BedItem* getBedBySleeper(uint32_t guid) const;
 		void setBedSleeper(BedItem* bed, uint32_t guid);
 		void removeBedSleeper(uint32_t guid);
+		bool reload(ReloadTypes_t reloadType);
 
 		Groups groups;
 		Map map;
 		Raids raids;
 
 	protected:
-		bool playerSayCommand(Player* player, const std::string& text);
 		bool playerSaySpell(Player* player, SpeakClasses type, const std::string& text);
 		void playerWhisper(Player* player, const std::string& text);
 		bool playerYell(Player* player, const std::string& text);
@@ -518,7 +514,6 @@ class Game
 
 		std::vector ToReleaseCreatures;
 		std::vector
-  ToReleaseItems;
-		std::vector commandTags;
 
 		size_t lastBucket = 0;
 
@@ -532,8 +527,6 @@ class Game
 
 		std::map bedSleepersMap;
 
-		Commands commands;
-
 		static constexpr int32_t LIGHT_LEVEL_DAY = 250;
 		static constexpr int32_t LIGHT_LEVEL_NIGHT = 40;
 		static constexpr int32_t SUNSET = 1305;
diff --git a/src/globalevent.cpp b/src/globalevent.cpp
index 53463a8..96c9d71 100644
--- a/src/globalevent.cpp
+++ b/src/globalevent.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/globalevent.h b/src/globalevent.h
index 1232ddf..b4ba1cb 100644
--- a/src/globalevent.h
+++ b/src/globalevent.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/groups.cpp b/src/groups.cpp
index f56956c..8b4460d 100644
--- a/src/groups.cpp
+++ b/src/groups.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/groups.h b/src/groups.h
index 2215678..e16adfb 100644
--- a/src/groups.h
+++ b/src/groups.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/guild.cpp b/src/guild.cpp
index 34db634..e6bed21 100644
--- a/src/guild.cpp
+++ b/src/guild.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/guild.h b/src/guild.h
index 1aeefe9..3085ec9 100644
--- a/src/guild.h
+++ b/src/guild.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/house.cpp b/src/house.cpp
index 88614f9..29f375c 100644
--- a/src/house.cpp
+++ b/src/house.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -82,7 +82,7 @@ void House::setOwner(uint32_t guid, bool updateDatabase/* = true*/, Player* play
 		setAccessList(SUBOWNER_LIST, "");
 		setAccessList(GUEST_LIST, "");
 
-		for (Door* door : doorList) {
+		for (Door* door : doorSet) {
 			door->setAccessList("");
 		}
 
@@ -116,7 +116,7 @@ void House::updateDoorDescription() const
 		}
 	}
 
-	for (const auto& it : doorList) {
+	for (const auto& it : doorSet) {
 		it->setSpecialDescription(ss.str());
 	}
 }
@@ -277,17 +277,17 @@ bool House::isInvited(const Player* player)
 void House::addDoor(Door* door)
 {
 	door->incrementReferenceCounter();
-	doorList.push_back(door);
+	doorSet.insert(door);
 	door->setHouse(this);
 	updateDoorDescription();
 }
 
 void House::removeDoor(Door* door)
 {
-	auto it = std::find(doorList.begin(), doorList.end(), door);
-	if (it != doorList.end()) {
+	auto it = doorSet.find(door);
+	if (it != doorSet.end()) {
 		door->decrementReferenceCounter();
-		doorList.erase(it);
+		doorSet.erase(it);
 	}
 }
 
@@ -299,7 +299,7 @@ void House::addBed(BedItem* bed)
 
 Door* House::getDoorByNumber(uint32_t doorId) const
 {
-	for (Door* door : doorList) {
+	for (Door* door : doorSet) {
 		if (door->getDoorId() == doorId) {
 			return door;
 		}
@@ -309,7 +309,7 @@ Door* House::getDoorByNumber(uint32_t doorId) const
 
 Door* House::getDoorByPosition(const Position& pos)
 {
-	for (Door* door : doorList) {
+	for (Door* door : doorSet) {
 		if (door->getPosition() == pos) {
 			return door;
 		}
diff --git a/src/house.h b/src/house.h
index 2b126c3..3d9b543 100644
--- a/src/house.h
+++ b/src/house.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@
 #define FS_HOUSE_H_EB9732E7771A438F9CD0EFA8CB4C58C4
 
 #include 
+#include 
 
 #include "container.h"
 #include "housetile.h"
@@ -212,10 +213,11 @@ class House
 			return houseTiles;
 		}
 
-		const std::list& getDoors() const {
-			return doorList;
+		const std::set& getDoors() const {
+			return doorSet;
 		}
 
+
 		void addBed(BedItem* bed);
 		const HouseBedItemList& getBeds() const {
 			return bedsList;
@@ -234,7 +236,7 @@ class House
 		Container transfer_container{ITEM_LOCKER1};
 
 		HouseTileList houseTiles;
-		std::list doorList;
+		std::set doorSet;
 		HouseBedItemList bedsList;
 
 		std::string houseName;
diff --git a/src/housetile.cpp b/src/housetile.cpp
index d206b48..f3fccf5 100644
--- a/src/housetile.cpp
+++ b/src/housetile.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/housetile.h b/src/housetile.h
index ba55d43..17ef634 100644
--- a/src/housetile.h
+++ b/src/housetile.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/ioguild.cpp b/src/ioguild.cpp
index 69675dc..b4ef9b5 100644
--- a/src/ioguild.cpp
+++ b/src/ioguild.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/ioguild.h b/src/ioguild.h
index d956c77..e5f058c 100644
--- a/src/ioguild.h
+++ b/src/ioguild.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/iologindata.cpp b/src/iologindata.cpp
index a2e5708..4fb9fbc 100644
--- a/src/iologindata.cpp
+++ b/src/iologindata.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/iologindata.h b/src/iologindata.h
index 9b58fdf..d207507 100644
--- a/src/iologindata.h
+++ b/src/iologindata.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/iomap.cpp b/src/iomap.cpp
index 3f6f426..197bf97 100644
--- a/src/iomap.cpp
+++ b/src/iomap.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/iomap.h b/src/iomap.h
index 9386141..5062e98 100644
--- a/src/iomap.h
+++ b/src/iomap.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/iomapserialize.cpp b/src/iomapserialize.cpp
index 0e83463..a6a5b9d 100644
--- a/src/iomapserialize.cpp
+++ b/src/iomapserialize.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/iomapserialize.h b/src/iomapserialize.h
index c7b269b..1a87c28 100644
--- a/src/iomapserialize.h
+++ b/src/iomapserialize.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/item.cpp b/src/item.cpp
index cb69843..acf2f1b 100644
--- a/src/item.cpp
+++ b/src/item.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/item.h b/src/item.h
index 45e1e58..fc92915 100644
--- a/src/item.h
+++ b/src/item.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/items.cpp b/src/items.cpp
index dcb1463..767ada3 100644
--- a/src/items.cpp
+++ b/src/items.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/items.h b/src/items.h
index af2f76e..6411e99 100644
--- a/src/items.h
+++ b/src/items.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/lockfree.h b/src/lockfree.h
index 0b9860c..7c8cc7b 100644
--- a/src/lockfree.h
+++ b/src/lockfree.h
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/luascript.cpp b/src/luascript.cpp
index 231d2b5..8099d24 100644
--- a/src/luascript.cpp
+++ b/src/luascript.cpp
@@ -1,6 +1,6 @@
 /**
  * Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017  Alejandro Mujica 
+ * Copyright (C) 2019 Sabrehaven and Mark Samman 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -676,6 +676,18 @@ void LuaScriptInterface::setCreatureMetatable(lua_State* L, int32_t index, const
 }
 
 // Get
+CombatDamage LuaScriptInterface::getCombatDamage(lua_State* L)
+{
+	CombatDamage damage;
+	damage.value = getNumber(L, -4);
+	damage.type = getNumber(L, -3);
+	damage.min = getNumber(L, -2);
+	damage.max = getNumber(L, -1);
+
+	lua_pop(L, 4);
+	return damage;
+}
+
 std::string LuaScriptInterface::getString(lua_State* L, int32_t arg)
 {
 	size_t len;
@@ -839,6 +851,16 @@ void LuaScriptInterface::pushBoolean(lua_State* L, bool value)
 	lua_pushboolean(L, value ? 1 : 0);
 }
 
+void LuaScriptInterface::pushCombatDamage(lua_State* L, const CombatDamage& damage)
+{
+	lua_pushnumber(L, damage.value);
+	lua_pushnumber(L, damage.type);
+	lua_pushnumber(L, damage.min);
+	lua_pushnumber(L, damage.max);
+	lua_pushnumber(L, damage.origin);
+}
+
+
 void LuaScriptInterface::pushPosition(lua_State* L, const Position& position, int32_t stackpos/* = 0*/)
 {
 	lua_createtable(L, 0, 4);
@@ -1465,6 +1487,13 @@ void LuaScriptInterface::registerFunctions()
 	registerEnum(SLOTP_DEPOT)
 	registerEnum(SLOTP_TWO_HAND)
 
+	// Use with combat functions
+	registerEnum(ORIGIN_NONE)
+	registerEnum(ORIGIN_CONDITION)
+	registerEnum(ORIGIN_SPELL)
+	registerEnum(ORIGIN_MELEE)
+	registerEnum(ORIGIN_RANGED)
+
 	// Use with house:getAccessList, house:setAccessList
 	registerEnum(GUEST_LIST)
 	registerEnum(SUBOWNER_LIST)
@@ -1533,6 +1562,31 @@ void LuaScriptInterface::registerFunctions()
 	registerEnum(RETURNVALUE_CANONLYUSEONESHIELD)
 	registerEnum(RETURNVALUE_NOPARTYMEMBERSINRANGE)
 	registerEnum(RETURNVALUE_YOUARENOTTHEOWNER)
+	registerEnum(RETURNVALUE_TRADEPLAYERFARAWAY)
+	registerEnum(RETURNVALUE_YOUDONTOWNTHISHOUSE)
+	registerEnum(RETURNVALUE_TRADEPLAYERALREADYOWNSAHOUSE)
+	registerEnum(RETURNVALUE_TRADEPLAYERHIGHESTBIDDER)
+	registerEnum(RETURNVALUE_YOUCANNOTTRADETHISHOUSE)
+	
+	registerEnum(RELOAD_TYPE_ALL)
+	registerEnum(RELOAD_TYPE_ACTIONS)
+	registerEnum(RELOAD_TYPE_CHAT)
+	registerEnum(RELOAD_TYPE_COMMANDS)
+	registerEnum(RELOAD_TYPE_CONFIG)
+	registerEnum(RELOAD_TYPE_CREATURESCRIPTS)
+	registerEnum(RELOAD_TYPE_EVENTS)
+	registerEnum(RELOAD_TYPE_GLOBAL)
+	registerEnum(RELOAD_TYPE_GLOBALEVENTS)
+	registerEnum(RELOAD_TYPE_ITEMS)
+	registerEnum(RELOAD_TYPE_MONSTERS)
+	registerEnum(RELOAD_TYPE_MOUNTS)
+	registerEnum(RELOAD_TYPE_MOVEMENTS)
+	registerEnum(RELOAD_TYPE_NPCS)
+	registerEnum(RELOAD_TYPE_QUESTS)
+	registerEnum(RELOAD_TYPE_RAIDS)
+	registerEnum(RELOAD_TYPE_SPELLS)
+	registerEnum(RELOAD_TYPE_TALKACTIONS)
+	registerEnum(RELOAD_TYPE_WEAPONS)
 
 	// _G
 	registerGlobalVariable("INDEX_WHEREEVER", INDEX_WHEREEVER);
@@ -1608,6 +1662,8 @@ void LuaScriptInterface::registerFunctions()
 	registerEnumIn("configKeys", ConfigManager::MAX_PACKETS_PER_SECOND)
 	registerEnumIn("configKeys", ConfigManager::NEWBIE_TOWN)
 	registerEnumIn("configKeys", ConfigManager::NEWBIE_LEVEL_THRESHOLD)
+	registerEnumIn("configKeys", ConfigManager::BLOCK_HEIGHT)
+	registerEnumIn("configKeys", ConfigManager::DROP_ITEMS)
 
 	// os
 	registerMethod("os", "mtime", LuaScriptInterface::luaSystemTime);
@@ -1646,6 +1702,8 @@ void LuaScriptInterface::registerFunctions()
 
 	registerMethod("Game", "startRaid", LuaScriptInterface::luaGameStartRaid);
 
+	registerMethod("Game", "reload", LuaScriptInterface::luaGameReload);
+
 	// Variant
 	registerClass("Variant", "", LuaScriptInterface::luaVariantCreate);
 
@@ -1853,10 +1911,6 @@ void LuaScriptInterface::registerFunctions()
 	registerMethod("Creature", "getMaxHealth", LuaScriptInterface::luaCreatureGetMaxHealth);
 	registerMethod("Creature", "setMaxHealth", LuaScriptInterface::luaCreatureSetMaxHealth);
 
-	registerMethod("Creature", "getMana", LuaScriptInterface::luaCreatureGetMana);
-	registerMethod("Creature", "addMana", LuaScriptInterface::luaCreatureAddMana);
-	registerMethod("Creature", "getMaxMana", LuaScriptInterface::luaCreatureGetMaxMana);
-
 	registerMethod("Creature", "getSkull", LuaScriptInterface::luaCreatureGetSkull);
 	registerMethod("Creature", "setSkull", LuaScriptInterface::luaCreatureSetSkull);
 
@@ -1914,6 +1968,9 @@ void LuaScriptInterface::registerFunctions()
 
 	registerMethod("Player", "getMagicLevel", LuaScriptInterface::luaPlayerGetMagicLevel);
 	registerMethod("Player", "getBaseMagicLevel", LuaScriptInterface::luaPlayerGetBaseMagicLevel);
+	registerMethod("Player", "getMana", LuaScriptInterface::luaPlayerGetMana);
+	registerMethod("Player", "addMana", LuaScriptInterface::luaPlayerAddMana);
+	registerMethod("Player", "getMaxMana", LuaScriptInterface::luaPlayerGetMaxMana);
 	registerMethod("Player", "setMaxMana", LuaScriptInterface::luaPlayerSetMaxMana);
 	registerMethod("Player", "getManaSpent", LuaScriptInterface::luaPlayerGetManaSpent);
 	registerMethod("Player", "addManaSpent", LuaScriptInterface::luaPlayerAddManaSpent);
@@ -2122,6 +2179,7 @@ void LuaScriptInterface::registerFunctions()
 
 	registerMethod("House", "getOwnerGuid", LuaScriptInterface::luaHouseGetOwnerGuid);
 	registerMethod("House", "setOwnerGuid", LuaScriptInterface::luaHouseSetOwnerGuid);
+	registerMethod("House", "startTrade", LuaScriptInterface::luaHouseStartTrade);
 
 	registerMethod("House", "getBeds", LuaScriptInterface::luaHouseGetBeds);
 	registerMethod("House", "getBedCount", LuaScriptInterface::luaHouseGetBedCount);
@@ -2196,6 +2254,7 @@ void LuaScriptInterface::registerFunctions()
 	registerMethod("Combat", "setArea", LuaScriptInterface::luaCombatSetArea);
 	registerMethod("Combat", "setCondition", LuaScriptInterface::luaCombatSetCondition);
 	registerMethod("Combat", "setCallback", LuaScriptInterface::luaCombatSetCallback);
+	registerMethod("Combat", "setOrigin", LuaScriptInterface::luaCombatSetOrigin);
 
 	registerMethod("Combat", "execute", LuaScriptInterface::luaCombatExecute);
 
@@ -2794,7 +2853,7 @@ int LuaScriptInterface::luaCreateCombatArea(lua_State* L)
 
 int LuaScriptInterface::luaDoAreaCombatHealth(lua_State* L)
 {
-	//doAreaCombatHealth(cid, type, pos, area, min, max, effect)
+	//doAreaCombatHealth(cid, type, pos, area, min, max, effect[, origin = ORIGIN_SPELL])
 	Creature* creature = getCreature(L, 1);
 	if (!creature && (!isNumber(L, 1) || getNumber(L, 1) != 0)) {
 		reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
@@ -2812,6 +2871,7 @@ int LuaScriptInterface::luaDoAreaCombatHealth(lua_State* L)
 		params.impactEffect = getNumber(L, 7);
 
 		CombatDamage damage;
+		damage.origin = getNumber(L, 8, ORIGIN_SPELL);
 		damage.type = combatType;
 		damage.value = normal_random(getNumber(L, 6), getNumber(L, 5));
 
@@ -2826,7 +2886,7 @@ int LuaScriptInterface::luaDoAreaCombatHealth(lua_State* L)
 
 int LuaScriptInterface::luaDoTargetCombatHealth(lua_State* L)
 {
-	//doTargetCombatHealth(cid, target, type, min, max, effect)
+	//doTargetCombatHealth(cid, target, type, min, max, effect[, origin = ORIGIN_SPELL])
 	Creature* creature = getCreature(L, 1);
 	if (!creature && (!isNumber(L, 1) || getNumber(L, 1) != 0)) {
 		reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
@@ -2848,6 +2908,7 @@ int LuaScriptInterface::luaDoTargetCombatHealth(lua_State* L)
 	params.impactEffect = getNumber(L, 6);
 
 	CombatDamage damage;
+	damage.origin = getNumber(L, 7, ORIGIN_SPELL);
 	damage.type = combatType;
 	damage.value = normal_random(getNumber(L, 4), getNumber(L, 5));
 
@@ -2858,7 +2919,7 @@ int LuaScriptInterface::luaDoTargetCombatHealth(lua_State* L)
 
 int LuaScriptInterface::luaDoAreaCombatMana(lua_State* L)
 {
-	//doAreaCombatMana(cid, pos, area, min, max, effect)
+	//doAreaCombatMana(cid, pos, area, min, max, effect[, origin = ORIGIN_SPELL])
 	Creature* creature = getCreature(L, 1);
 	if (!creature && (!isNumber(L, 1) || getNumber(L, 1) != 0)) {
 		reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
@@ -2873,6 +2934,7 @@ int LuaScriptInterface::luaDoAreaCombatMana(lua_State* L)
 		params.impactEffect = getNumber(L, 6);
 
 		CombatDamage damage;
+		damage.origin = getNumber(L, 7, ORIGIN_SPELL);
 		damage.type = COMBAT_MANADRAIN;
 		damage.value = normal_random(getNumber(L, 4), getNumber(L, 5));
 
@@ -2888,7 +2950,7 @@ int LuaScriptInterface::luaDoAreaCombatMana(lua_State* L)
 
 int LuaScriptInterface::luaDoTargetCombatMana(lua_State* L)
 {
-	//doTargetCombatMana(cid, target, min, max, effect)
+	//doTargetCombatMana(cid, target, min, max, effect[, origin = ORIGIN_SPELL)
 	Creature* creature = getCreature(L, 1);
 	if (!creature && (!isNumber(L, 1) || getNumber(L, 1) != 0)) {
 		reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
@@ -2907,6 +2969,7 @@ int LuaScriptInterface::luaDoTargetCombatMana(lua_State* L)
 	params.impactEffect = getNumber(L, 5);
 
 	CombatDamage damage;
+	damage.origin = getNumber(L, 6, ORIGIN_SPELL);
 	damage.type = COMBAT_MANADRAIN;
 	damage.value = normal_random(getNumber(L, 3), getNumber(L, 4));
 
@@ -4144,6 +4207,25 @@ int LuaScriptInterface::luaGameStartRaid(lua_State* L)
 	return 1;
 }
 
+int LuaScriptInterface::luaGameReload(lua_State* L)
+{
+	// Game.reload(reloadType)
+	ReloadTypes_t reloadType = getNumber(L, 1);
+	if (!reloadType) {
+		lua_pushnil(L);
+		return 1;
+	}
+
+	if (reloadType == RELOAD_TYPE_GLOBAL) {
+		pushBoolean(L, g_luaEnvironment.loadFile("data/global.lua") == 0);
+	}
+	else {
+		pushBoolean(L, g_game.reload(reloadType));
+	}
+	lua_gc(g_luaEnvironment.getLuaState(), LUA_GCCOLLECT, 0);
+	return 1;
+}
+
 // Variant
 int LuaScriptInterface::luaVariantCreate(lua_State* L)
 {
@@ -6575,50 +6657,6 @@ int LuaScriptInterface::luaCreatureSetMaxHealth(lua_State* L)
 	return 1;
 }
 
-int LuaScriptInterface::luaCreatureGetMana(lua_State* L)
-{
-	// creature:getMana()
-	const Creature* creature = getUserdata(L, 1);
-	if (creature) {
-		lua_pushnumber(L, creature->getMana());
-	} else {
-		lua_pushnil(L);
-	}
-	return 1;
-}
-
-int LuaScriptInterface::luaCreatureAddMana(lua_State* L)
-{
-	// creature:addMana(manaChange[, animationOnLoss = false])
-	Creature* creature = getUserdata(L, 1);
-	if (!creature) {
-		lua_pushnil(L);
-		return 1;
-	}
-
-	int32_t manaChange = getNumber(L, 2);
-	bool animationOnLoss = getBoolean(L, 3, false);
-	if (!animationOnLoss && manaChange < 0) {
-		creature->changeMana(manaChange);
-	} else {
-		g_game.combatChangeMana(nullptr, creature, manaChange);
-	}
-	pushBoolean(L, true);
-	return 1;
-}
-
-int LuaScriptInterface::luaCreatureGetMaxMana(lua_State* L)
-{
-	// creature:getMaxMana()
-	const Creature* creature = getUserdata(L, 1);
-	if (creature) {
-		lua_pushnumber(L, creature->getMaxMana());
-	} else {
-		lua_pushnil(L);
-	}
-	return 1;
-}
-
 int LuaScriptInterface::luaCreatureGetSkull(lua_State* L)
 {
 	// creature:getSkull()
@@ -7191,15 +7229,15 @@ int LuaScriptInterface::luaPlayerGetExperience(lua_State* L)
 
 int LuaScriptInterface::luaPlayerAddExperience(lua_State* L)
 {
-	// player:addExperience(experience[, sendText = false[, applyStages = true])
+	// player:addExperience(experience[, sendText = false])
 	Player* player = getUserdata(L, 1);
 	if (player) {
 		int64_t experience = getNumber(L, 2);
 		bool sendText = getBoolean(L, 3, false);
-		bool applyStages = getBoolean(L, 4, true);
-		player->addExperience(experience, sendText, applyStages);
+		player->addExperience(nullptr, experience, sendText);
 		pushBoolean(L, true);
-	} else {
+	}
+	else {
 		lua_pushnil(L);
 	}
 	return 1;
@@ -7255,6 +7293,56 @@ int LuaScriptInterface::luaPlayerGetBaseMagicLevel(lua_State* L)
 	return 1;
 }
 
+int LuaScriptInterface::luaPlayerGetMana(lua_State* L)
+{
+	// player:getMana()
+	const Player* player = getUserdata(L, 1);
+	if (player) {
+		lua_pushnumber(L, player->getMana());
+	}
+	else {
+		lua_pushnil(L);
+	}
+	return 1;
+}
+
+int LuaScriptInterface::luaPlayerAddMana(lua_State* L)
+{
+	// player:addMana(manaChange[, animationOnLoss = false])
+	Player* player = getUserdata(L, 1);
+	if (!player) {
+		lua_pushnil(L);
+		return 1;
+	}
+
+	int32_t manaChange = getNumber