Last active
March 11, 2016 15:52
-
-
Save dbjorkholm/4232630711b0f4e7c41e to your computer and use it in GitHub Desktop.
[TFS 1.1+] Zombie Event
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function onPrepareDeath(player, killer) | |
if not ZombieEvent.running or not ZombieEvent:isInRange(player:getPosition()) or player:getStorageValue(ZombieEvent.eventStorage) ~= 1 then | |
return true | |
end | |
local killerName = "a field item" | |
if killer then | |
local master = killer:getMaster() | |
if master and master ~= killer and master:isPlayer() then | |
killer = master | |
end | |
killerName = killer:isMonster() and killer:getType():getNameDescription() or killer:getName() | |
end | |
ZombieEvent:onPlayerDeath(player:getName(), killerName) | |
return false | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function onThink(interval, lastExecution, thinkInterval) | |
if #Game.getPlayers() < ZombieEvent.minPlayers | |
or ZombieEvent.nextExecution > os.time() | |
or ZombieEvent.startingUp | |
or ZombieEvent.running then | |
return true | |
end | |
ZombieEvent:init() | |
return true | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local config = { | |
minutesToStart = 10, | |
minutesToNextExecution = 15, | |
firstSpawnInterval = 10 * 1000, | |
spawnInterval = 15 * 1000, | |
monsterName = "ZombieEvent", | |
rewards = { | |
{itemId = 2160, count = 10}, | |
{itemId = 2160, count = 5}, | |
{itemId = 2160, count = 3}, | |
}, | |
spawnArea = {fromPosition = Position(1000, 1000, 7), toPosition = Position(1000, 1000, 7)}, | |
waitingRoomArea = {fromPosition = Position(1000, 1000, 7), toPosition = Position(1000, 1000, 7)}, | |
teleport = { | |
enabled = false, | |
position = Position(1000, 1000, 7), | |
actionId = 1000, | |
}, | |
} | |
local function getRandomSpawnPosition(fromPosition, toPosition) | |
local random = math.random | |
return Position(random(fromPosition.x, toPosition.x), random(fromPosition.y, toPosition.y), random(fromPosition.z, toPosition.z)) | |
end | |
local function getNumberOrdinal(number) | |
if number >= 11 and number <= 19 then | |
return "th" | |
end | |
local number = number % 10 | |
local ordinals = {"st", "nd", "rd"} | |
return ordinals[number] or "th" | |
end | |
local function isInRange(pos, fromPos, toPos) | |
return pos.x >= fromPos.x and pos.y >= fromPos.y and pos.z >= fromPos.z and pos.x <= toPos.x and pos.y <= toPos.y and pos.z <= toPos.z | |
end | |
if not ZombieEvent then | |
ZombieEvent = { | |
players = { }, | |
zombies = { }, | |
running = false, | |
startingUp = false, | |
spawnEvent = nil, | |
minPlayers = 10, | |
nextExecution = 0, | |
round = 1, | |
eventStorage = 1234, | |
eventName = "ZombieEvent", | |
} | |
end | |
-- Functions A-Z | |
function ItemType.getNameDescription(self, count) | |
local count = count or 1 | |
local description = "" | |
if self:isRune() then | |
description = string.format("%s %s (%d charges)", self:getArticle(), self:getName(), count) | |
elseif self:isStackable() and count > 1 then | |
description = string.format("%d %s", count, self:getPluralName()) | |
elseif self:getArticle() ~= '' then | |
description = string.format("%s %s", self:getArticle(), self:getName()) | |
else | |
description = self:getName() | |
end | |
return description | |
end | |
function ZombieEvent.addPlayer(self, player) | |
if not self.startingUp or self.running then | |
return | |
end | |
-- Send Message | |
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have joined the Zombie Event!") | |
-- Add Storage | |
player:setStorageValue(self.eventStorage, 1) | |
-- Register Event | |
player:registerEvent(self.eventName) | |
-- Teleport Player | |
local waitingRoomPosition = getRandomSpawnPosition(config.waitingRoomArea.fromPosition, config.waitingRoomArea.toPosition) | |
player:getPosition():sendMagicEffect(CONST_ME_POFF) | |
player:teleportTo(waitingRoomPosition) | |
waitingRoomPosition:sendMagicEffect(CONST_ME_TELEPORT) | |
self.players[#self.players + 1] = player:getName() | |
end | |
function ZombieEvent.addReward(self, playerName) | |
local reward = config.rewards[#self.players] | |
if not reward then | |
return | |
end | |
local player = Player(playerName) | |
if not player then | |
return | |
end | |
local rewardItem = Game.createItem(reward.itemId, reward.count) | |
if not rewardItem then | |
return | |
end | |
local ret = player:addItemEx(rewardItem) | |
if ret ~= RETURNVALUE_NOERROR then | |
local inbox = player:getInbox() | |
if inbox then | |
inbox:addItemEx(rewardItem, INDEX_WHEREEVER, FLAG_NOLIMIT) | |
end | |
end | |
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format('You received %s for coming in %d%s place. %s', ItemType(reward.itemId):getNameDescription(reward.count), #self.players, getNumberOrdinal(#self.players), ret ~= 0 and "The reward was sent to your inbox due not enough capacity or room in your backpack." or "")) | |
end | |
function ZombieEvent.addTeleport(self) | |
if not self.startingUp or not config.teleport.enabled then | |
return | |
end | |
local tile = Tile(config.teleport.position) | |
if not tile or tile:getItemById(1387) then | |
return | |
end | |
local teleport = Game.createItem(1387, 1, config.teleport.position) | |
if not teleport then | |
return | |
end | |
teleport:setActionId(config.teleport.actionId) | |
end | |
function ZombieEvent.broadcastMessage(self, type, message) | |
if not self.running or #self.players == 0 then | |
return | |
end | |
for i = 1, #self.players do | |
local tmpPlayer = Player(self.players[i]) | |
if tmpPlayer then | |
tmpPlayer:sendTextMessage(type, message) | |
end | |
end | |
end | |
function ZombieEvent.init(self) | |
if self.startingUp or self.running then | |
return | |
end | |
for i = 0, config.minutesToStart do | |
if i == config.minutesToStart then | |
addEvent(function(self) self:start() end, i * 60000, self) | |
else | |
addEvent(Game.broadcastMessage, i * 60000, string.format('The Zombie Event will start in %d minute%s. You can join the event by typing !joinzombie.', config.minutesToStart - i, config.minutesToStart - i ~= 1 and "s" or ""), MESSAGE_EVENT_ADVANCE) | |
end | |
end | |
self.startingUp = true | |
self:addTeleport() | |
end | |
function ZombieEvent.isInRange(self, position) | |
return isInRange(position, config.spawnArea.fromPosition, config.spawnArea.toPosition) | |
end | |
function ZombieEvent.onPlayerDeath(self, playerName, killerName) | |
if not self.running or #self.players <= 1 then | |
return | |
end | |
self:addReward(playerName) | |
self:removePlayer(playerName, string.format("You were killed by %s", killerName)) | |
if #self.players ~= 1 then | |
return | |
end | |
self:onWinner(self.players[1]) | |
end | |
function ZombieEvent.onWinner(self, playerName) | |
if not self.running or #self.players ~= 1 then | |
return | |
end | |
local winner = Player(playerName) | |
local round = self.round ~= 1 and self.round - 1 or self.round | |
if winner then | |
self:addReward(playerName) | |
self:releasePlayer(playerName, string.format("You won the Zombie Event in the %d%s round. Congratulations!", round, getNumberOrdinal(round))) | |
Game.broadcastMessage(string.format("%s is the winner of the Zombie Event in the %d%s round. Congratulations!", winner:getName(), round, getNumberOrdinal(round)), MESSAGE_EVENT_ADVANCE) | |
end | |
self:stop("The Zombie Event is over.") | |
end | |
function ZombieEvent.releasePlayer(self, playerName, message) | |
local player = Player(playerName) | |
if not player then | |
return | |
end | |
-- Send Text Message | |
if message then | |
player:sendTextMessage(MESSAGE_INFO_DESCR, message) | |
end | |
-- Add Health/Mana | |
player:addHealth(player:getMaxHealth()) | |
player:addMana(player:getMaxMana()) | |
-- Remove Storage | |
player:setStorageValue(self.eventStorage, -1) | |
-- Unregister Event | |
player:unregisterEvent(self.eventName) | |
-- Teleport player to temple | |
local templePosition = player:getTown():getTemplePosition() | |
player:teleportTo(templePosition) | |
templePosition:sendMagicEffect(CONST_ME_TELEPORT, player) | |
end | |
function ZombieEvent.removePlayer(self, playerName, message) | |
if not self.running or #self.players == 0 then | |
return | |
end | |
for i = 1, #self.players do | |
if self.players[i] == playerName then | |
self:releasePlayer(playerName, message) | |
table.remove(self.players, i) | |
return | |
end | |
end | |
end | |
function ZombieEvent.removeTeleport(self) | |
if not config.teleport.enabled then | |
return | |
end | |
local tile = Tile(config.teleport.position) | |
if not tile then | |
return | |
end | |
local teleport = tile:getItemById(1387) | |
if not teleport then | |
return | |
end | |
teleport:remove() | |
end | |
function ZombieEvent.spawnZombies(self) | |
if not self.running then | |
return | |
end | |
local amount = self.round * 2 - 1 | |
for i = 1, amount do | |
local tmpMonster = Game.createMonster(config.monsterName, getRandomSpawnPosition(config.spawnArea.fromPosition, config.spawnArea.toPosition), true) | |
if tmpMonster then | |
self.zombies[#self.zombies + 1] = tmpMonster:getId() | |
end | |
end | |
self:broadcastMessage(MESSAGE_EVENT_ADVANCE, string.format("The %d%s wave of zombies will spawn shortly. Prepare yourself!", self.round, getNumberOrdinal(self.round))) | |
self.round = self.round + 1 | |
self.spawnEvent = addEvent(function(self) self:spawnZombies() end, config.spawnInterval, self) | |
end | |
function ZombieEvent.start(self) | |
if not self.startingUp or self.running then | |
return | |
end | |
if #self.players < self.minPlayers then | |
self:stop("The Zombie Event did not start due to not enough participants. You were sent back to your hometown.") | |
Game.broadcastMessage("The Zombie Event did not start due to not enough participants.", MESSAGE_EVENT_ADVANCE) | |
return | |
end | |
for i = 1, #self.players do | |
local tmpPlayer = Player(self.players[i]) | |
if tmpPlayer then | |
tmpPlayer:teleportTo(getRandomSpawnPosition(config.spawnArea.fromPosition, config.spawnArea.toPosition)) | |
end | |
end | |
self.running = true | |
self.startingUp = false | |
self.round = 1 | |
self.spawnEvent = addEvent(function(self) self:spawnZombies() end, config.firstSpawnInterval, self) | |
self:removeTeleport() | |
self:broadcastMessage(MESSAGE_EVENT_ADVANCE, "The first wave of zombies will spawn shortly. Prepare yourself!") | |
Game.broadcastMessage("The Zombie Event has started. Good luck to all participants!", MESSAGE_EVENT_ADVANCE) | |
end | |
function ZombieEvent.stop(self, message) | |
-- Remove Players | |
if #self.players ~= 0 then | |
for i = 1, #self.players do | |
self:releasePlayer(self.players[i], message) | |
end | |
end | |
-- Remove Zombies | |
if #self.zombies ~= 0 then | |
for i = 1, #self.zombies do | |
local tmpMonster = Monster(self.zombies[i]) | |
if tmpMonster then | |
tmpMonster:remove() | |
end | |
end | |
end | |
-- Stop spawn event | |
if self.spawnEvent then | |
stopEvent(self.spawnEvent) | |
end | |
-- Remove Teleport | |
self:removeTeleport() | |
self.players = { } | |
self.zombies = { } | |
self.running = false | |
self.startingUp = false | |
self.round = 1 | |
self.nextExecution = os.time() + config.minutesToNextExecution | |
self.spawnEvent = nil | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<monster name="Zombie" nameDescription="a zombie" race="undead" experience="0" speed="100" manacost="0"> | |
<health now="500" max="500"/> | |
<look type="311" corpse="0"/> | |
<targetchange interval="4000" chance="10"/> | |
<strategy attack="100" defense="0"/> | |
<flags> | |
<flag summonable="0"/> | |
<flag attackable="1"/> | |
<flag hostile="1"/> | |
<flag illusionable="0"/> | |
<flag convinceable="0"/> | |
<flag pushable="0"/> | |
<flag canpushitems="1"/> | |
<flag canpushcreatures="1"/> | |
<flag targetdistance="1"/> | |
<flag staticattack="90"/> | |
<flag runonhealth="0"/> | |
</flags> | |
<attacks> | |
<attack name="melee" interval="2000" min="999999" max="999999" /> | |
</attacks> | |
<defenses armor="15" defense="15"/> | |
<immunities> | |
<immunity death="1"/> | |
<immunity fire="1"/> | |
<immunity holy="1"/> | |
<immunity physical="1"/> | |
<immunity energy="1"/> | |
<immunity ice="1"/> | |
<immunity earth="1"/> | |
<immunity drown="1"/> | |
<immunity drunk="1"/> | |
<immunity lifedrain="1"/> | |
<immunity paralyze="1"/> | |
</immunities> | |
<voices interval="5000" chance="10"> | |
<voice sentence="Mst.... klll...."/> | |
<voice sentence="Whrrrr... ssss.... mmm.... grrrrl"/> | |
<voice sentence="Dnnnt... cmmm... clsrrr...."/> | |
<voice sentence="Httt.... hmnnsss..."/> | |
</voices> | |
</monster> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local function pushPlayer(player, text, position, fromPosition) | |
if not player then | |
return | |
end | |
player:sendCancelMessage(text) | |
player:teleportTo(fromPosition) | |
position:sendMagicEffect(CONST_ME_TELEPORT) | |
fromPosition:sendMagicEffect(CONST_ME_TELEPORT) | |
end | |
function onStepIn(creature, item, position, fromPosition) | |
local player = creature:getPlayer() | |
if not player then | |
return true | |
end | |
if not ZombieEvent.startingUp then | |
pushPlayer(player, "The event is not running at the moment.", position, fromPosition) | |
return true | |
end | |
if ZombieEvent.running then | |
pushPlayer(player, "The event has already started.", position, fromPosition) | |
return true | |
end | |
if player:getGroup():getAccess() then | |
pushPlayer(player, "Staff members are not allowed to join the event.", position, fromPosition) | |
return true | |
end | |
if player:isPzLocked() then | |
pushPlayer(player, "You cannot join the event while you are in a fight.", position, fromPosition) | |
return true | |
end | |
if player:getStorageValue(ZombieEvent.eventStorage) ~= -1 then | |
pushPlayer(player, "You have already joined the event.", position, fromPosition) | |
return true | |
end | |
ZombieEvent:addPlayer(player) | |
return true | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function onSay(player, words, param) | |
if not ZombieEvent.startingUp then | |
player:sendCancelMessage("The event is not running at the moment.") | |
return false | |
end | |
if ZombieEvent.running then | |
player:sendCancelMessage("The event has already started.") | |
return false | |
end | |
if player:getGroup():getAccess() then | |
player:sendCancelMessage("Staff members are not allowed to join the event.") | |
return false | |
end | |
if player:isPzLocked() then | |
player:sendCancelMessage("You cannot join the event while you are in a fight.") | |
return false | |
end | |
if player:getStorageValue(ZombieEvent.eventStorage) ~= -1 then | |
player:sendCancelMessage("You have already joined the event.") | |
return false | |
end | |
ZombieEvent:addPlayer(player) | |
return false | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment