Now it is working THXYou need to change the walkPaths in the twdLib. You should look on the positions on the old map and see how i configured them.
You need set pos everytime it going to turn.
Hi, first of all awesome feature, thank you very much.
It works out pretty good, only problem I have is by adding waves.
I add a wave, change the maxWaveLevel = 3 to =4
And added a new wave:
[4] = {
interval = 1000,
goldBonus = 125,
expBonus = 4000,
monsters = {
{name = "Rat", count = 15, interval = 500},
{name = "Bug", count = 10, interval = 500}
}
}
They also spawn, all no problem, only thing is that the player does not "win" the game anymore.
It looks like there's a another wave comming, but obviously there isnt. Any suggestions? No errors on the console.
TFS 1.1~
Hello, well i thougt about release a christmas present to everyone in otland. Here you go guys:
Cheers @Ninja and @Limos for the help
Features:
First open data/actions/actions.xml and paste this line:
- Unlimited waves can be configured!
- Monsters health, gold drop and speed can be configured!
- Different monsters, counts and space between the monster can be configred!
- Unlimited turrets can be added!
- Turrets cost, upgrade, sell, range, color and attackSpeed can be also easily configured!
- Reward of wining a wave can also be configured, exp and gold wise
Code:<action itemid="2557" script="twdHammer.lua" allowfaruse="1"/>
Then go to data/actions/scripts and create new lua and name it "twdHammer" and paste this:
Code:dofile('data/libs/TWD/towerDefenseLib.lua') function onUse(player, item, fromPosition, target, toPosition, isHotkey) if player:getStorageValue(playingGameStorage) ~= 1 then return false end local tile = toPosition:getTile() if tile then if not tile:hasFlag(TILESTATE_PROTECTIONZONE) or tile:hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID) then player:sendCancelMessage("You cannot place the turret here.") return true end end if target:isItem() then local modalWindow = ModalWindow(100, "Build Turret", "Here you can select variations of turrets to build.") local turret, cfgTable = turrets.allTurretsId for i = 1, #turret do turret = turrets.allTurretsId[i] cfgTable = turrets[turret].cfg modalWindow:addChoice(turret, string.format("%s [%s coins]", cfgTable.turretName, cfgTable[1].buildPrice)) end modalWindow:addButton(0, "Build") modalWindow:setDefaultEnterButton(0) modalWindow:addButton(1, "Cancel") modalWindow:setDefaultEscapeButton(1) modalWindow:sendToPlayer(player) turretPosition = toPosition elseif target:isNpc() and target:getName() == "Turret" then local table = turrets[target:getOutfit().lookType] local lvl = target:getTurretLevel() local cfg, cfgCombat = table.cfg[lvl], table.combat[lvl] local turrentInfo = string.format("Turret Information\n----------------------------\nTurret Level: %s\nAttack Type: %s\nRange SQM: %sx%s\nTurret Damage: [%s - %s]\nAttack Speed: %s\nSell/Upgrade Price: [%s / %s]", lvl, string.upper(cfgCombat.attackType), cfg.rangeX, cfg.rangeY, cfgCombat.dmgValues[1], cfgCombat.dmgValues[2], cfg.attackSpeed, cfg.sellPrice, cfg.upgradePrice) local playerInfo = string.format("Player Information\n----------------------------\nWave Level: %s\nYour Coins: %s", getWaveLevel(), player:getCoins()) local modalWindow = ModalWindow(101, "Information", string.format("%s\n\n%s", turrentInfo, playerInfo)) if lvl < 3 then modalWindow:addChoice(0, "Upgrade") end modalWindow:addChoice(1, "Sell") modalWindow:addButton(0, "Yes") modalWindow:setDefaultEnterButton(0) modalWindow:addButton(0x01, "Cancel") modalWindow:setDefaultEscapeButton(1) modalWindow:sendToPlayer(player) targetTurret = target end return true end
Now go into data/creaturescripts/creaturescripts.xml and paste these lines:
Code:<event type="death" name="TWDDeath" script="twdEvent/twdDeath.lua"/> <event type="preparedeath" name="TWDOnLose" script="twdEvent/twdOnLose.lua"/> <event type="modalwindow" name="TWDBuildWindow" script="twdEvent/twdBuildWindow.lua"/> <event type="modalwindow" name="TWDOtherWindow" script="twdEvent/twdOtherWindow.lua"/> <event type="healthchange" name="TWDHealthChange" script="twdEvent/twdHealthChange.lua"/>
And now go to data/creaturescripts/scripts and create new folder and name it twdEvent and now create these lua's files:
twdBuildWindow.lua
Code:dofile('data/libs/TWD/towerDefenseLib.lua') function onModalWindow(player, modalWindowId, buttonId, choiceId) if modalWindowId ~= 100 then -- Not our window return false elseif buttonId == 1 then -- Cancel return false end local choice = turrets[choiceId] if not choice then return false end local table = choice.cfg[1] if player:getCoins() < choice.cfg[1].buildPrice then player:sendCancelMessage("You don't have enough of coins.") return false end local npc = Game.createNpc("Turret", turretPosition, false, true) if not npc then return false end player:addCoins(-choice.cfg[1].buildPrice) player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have total ".. player:getCoins() .." coins.") local setColor = table.colorId npc:setOutfit({lookType = choiceId, lookHead = setColor , lookBody = setColor, lookLegs = setColor, lookFeet = setColor}) npc:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) return true end
twdDeath.lua
Code:dofile('data/libs/TWD/towerDefenseLib.lua') local function sendToNextWave(cid) local player = Player(cid) if not player then return false end local waveLevel = getWaveLevel() setWaveLevel(waveLevel + 1) -- Let's add + 1 to our current wave waveLevel = getWaveLevel() -- Let's refresh the variable if waveLevel <= waves.maxWaveLevel then -- Let's make sure there is more waves / Else end the event local waveTable = waves[waveLevel] player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have advanced to wave level %s, gained %s coins and %s experience points.", waveLevel, waveTable.goldBonus, waveTable.expBonus)) startNextWave(waveLevel, twdConfig.startNextWaveTime) Game.setStorageValue(totalMonsterKillCountGlobalStorage, 0) player:addCoins(waveTable.goldBonus) player:addExperience(waveTable.expBonus, true) player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have now total ".. player:getCoins() .." coins.") else sendReward(cid) resetEvent() end end function onDeath(creature, corpse, killer, mostDamageKiller, unjustified, mostDamageUnjustified) local player = getPlayerInEvent(20, 20) if not player then -- Make sure that the players exsist in the arena, to prevent errors return true end if killer and killer:isNpc() then local cfg = monsters[creature:getName()] creature:say("+" ..cfg.coins, TALKTYPE_MONSTER_SAY) player:addCoins(cfg.coins) player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have total ".. player:getCoins() .." coins.") end Game.setStorageValue(totalMonsterKillCountGlobalStorage, Game.getStorageValue(totalMonsterKillCountGlobalStorage) + 1) if Game.getStorageValue(totalMonsterKillCountGlobalStorage) >= Game.getStorageValue(totalMonsterCountGlobalStorage) then sendToNextWave(player:getId()) end return true end
twdHealthChange.lua
Code:function onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin) if primaryType == COMBAT_HEALING then return false end return primaryDamage, primaryType, secondaryDamage, secondaryType end
twdOnLose.lua
Code:dofile('data/libs/TWD/towerDefenseLib.lua') function onPrepareDeath(player, killer) if player:getStorageValue(playingGameStorage) ~= 1 then return true end player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have lost the Tower Of Defence Event.") player:resetValues() addEvent(resetEvent, twdConfig.resetEventTime * 1000) return false end
twdOtherWindow.lua
Code:dofile('data/libs/TWD/towerDefenseLib.lua') function onModalWindow(player, modalWindowId, buttonId, choiceId) if modalWindowId ~= 101 then -- Not our window return false elseif buttonId == 1 then -- Cancel return false end local npc = targetTurret local npcLvl = npc:getTurretLevel() local table = turrets[npc:getOutfit().lookType].cfg[npcLvl] if choiceId == 0 then if player:getCoins() < table.upgradePrice then player:sendCancelMessage("You don't have enough of coins.") return false end npcLvl = npcLvl + 1 local setColor = table.colorId npc:setOutfit({lookType = npc:getOutfit().lookType, lookHead = setColor , lookBody = setColor, lookLegs = setColor, lookFeet = setColor, lookAddons = npcLvl}) npc:getPosition():sendMagicEffect(math.random(CONST_ME_FIREWORK_YELLOW, CONST_ME_FIREWORK_BLUE)) player:addCoins(-table.upgradePrice) player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have total ".. player:getCoins() .." coins.") targetTurret = nil else player:addCoins(table.sellPrice) player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have total ".. player:getCoins() .." coins.") npc:say("+" ..table.sellPrice, TALKTYPE_MONSTER_SAY) player:addCoins(table.sellPrice) npc:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED) npc:remove() targetTurret = nil end return true end
Part 2 can be founded below!
dofile('data/libs/TWD/towerDefenseSpellsArea.lua')
dofile('data/libs/TWD/towerDefenseConfig.lua')
targetTurret = nil
turretPosition = nil
local twdEvents = {
"TWDOnLose",
"TWDBuildWindow",
"TWDOtherWindow",
"TWDHealthChange"
}
function Player.resetValues(self)
self:removeItem(2557, 1)
self:setStorageValue(coinStorage, 0)
self:addHealth(self:getMaxHealth())
self:setStorageValue(playingGameStorage, 0)
self:teleportTo(self:getTown():getTemplePosition())
for i = 1, #twdEvents do
self:unregisterEvent(twdEvents[i])
end
end
function sendReward(cid)
local player = Player(cid)
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have won the Tower Of Defense Event.")
player:addItem(2160, 10)
player:resetValues()
end
function resetEvent()
turretPosition = nil
targetTurret = nil
setWaveLevel(0)
Game.setStorageValue(totalMonsterKillCountGlobalStorage, 0)
Game.setStorageValue(totalMonsterCountGlobalStorage, 0)
local specs, turrets = Game.getSpectators(eventCenterPosition, false, false, 40, 40, 40, 40)
for i = 1, #specs do
turrets = specs[i]
if turrets:isNpc() and turrets:getName() == "Turret" then
turrets:remove()
end
end
end
-- Everytime the monster need to turn, you have to write the position of the turning point and where it should walk after it reached the point.
local walkPaths = {
Position(1003, 1076, 7),
Position(1007, 1076, 7),
Position(1007, 1085, 7),
Position(998, 1085, 7),
Position(998, 1091, 7),
Position(1009, 1091, 7),
Position(1009, 1096, 7),
Position(1014, 1096, 7),
Position(1014, 1091, 7),
Position(1021, 1091, 7),
Position(1021, 1079, 7),
Position(1018, 1079, 7),
Position(1018, 1075, 7)
}
local function monsterWalkTo(cid, fromPos, toPos, state) -- Limos
local toPosState = toPos[state]
if not toPosState then
return false
end
if fromPos.y == toPosState.y then
fromPos.x = fromPos.x > toPosState.x and fromPos.x - 1 or (fromPos.x < toPosState.x and fromPos.x + 1 or fromPos.x)
else
fromPos.y = fromPos.y > toPosState.y and fromPos.y - 1 or (fromPos.y < toPosState.y and fromPos.y + 1 or fromPos.y)
end
local monster = Monster(cid)
if not monster then
return false
end
monster:teleportTo(fromPos, true)
if fromPos.x == toPosState.x and fromPos.y == toPosState.y then
state = state + 1
end
local speed = monsters[monster:getName()].speed
if not speed then
speed = 0
end
addEvent(monsterWalkTo, 1000 - speed, cid, fromPos, toPos, state)
end
function Npc.searchTarget(self, xRange, yRange)
local target = self:getTarget()local specs, creatures = Game.getSpectators(self:getPosition(), false, false, xRange, xRange, yRange, yRange)
for i = 1, #specs do
if target then -- We already have a target, which is in range. Let's break the loop then
break
end
creatures = specs[i]
if creatures:isMonster() then -- Let's pick a target, which is a monster
return self:setTarget(creatures)
end
end
end
function Npc.shootSpell(self, attackType, target, combat, area, min, max, magicEffect, distEffect)
if attackType == "aoe" then
doAreaCombatHealth(self, combat, self:getPosition(), area, -min, -max, magicEffect)
elseif attackType == "targetAoe" then
doAreaCombatHealth(self, combat, target:getPosition(), area, -min, -max, magicEffect)
self:getPosition():sendDistanceEffect(target:getPosition(), distEffect)
else
doTargetCombatHealth(self, target, combat, -min, -max, magicEffect)
self:getPosition():sendDistanceEffect(target:getPosition(), distEffect)
end
end
function getPlayerInEvent(xRange, yRange)
local player
if player then
return player
end
local specs = Game.getSpectators(eventCenterPosition, false, true, xRange, xRange, yRange, yRange)
for i = 1, #specs do
if specs[i]:getStorageValue(playingGameStorage) == 1 then
player = specs[i]
return player
end
end
end
local function summonMonster(name)
local monster = Game.createMonster(name .."_TWD", summonMonsterPosition, false, true)
if monster then
monster:setDirection(EAST)
monsterWalkTo(monster:getId(), monster:getPosition(), walkPaths, 1)
summonMonsterPosition:sendMagicEffect(CONST_ME_TELEPORT)
monster:changeSpeed(-monster:getSpeed() + 130)
local extraHealth = monsters[name].extraHealth
if extraHealth then
monster:setMaxHealth(monster:getMaxHealth() + extraHealth)
monster:addHealth(monster:getMaxHealth())
end
end
end
function startWaveLevel(level) -- Ninja
local table, total = waves, 0
for a = 1, #waves do
table = waves[level]
for b = 1, #table.monsters do
for c = 1, table.monsters[b].count do
addEvent(function()
addEvent(summonMonster, b * table.monsters[b].interval, table.monsters[b].name)
end, c * table.interval)
end
total = total + table.monsters[b].count
end
break
end
Game.setStorageValue(totalMonsterCountGlobalStorage, total)
end
function startNextWave(level, interval)
addEvent(startWaveLevel, interval * 1000, level)
end
function Npc.setTurretLevel(self, level)
if level > 3 then
level = 3
end
local lookId = self:getOutfit().lookType
local setColor = turrets[lookId].cfg[level].colorId
self:setOutfit({lookType = lookId, lookHead = setColor , lookBody = setColor, lookLegs = setColor, lookFeet = setColor, lookAddons = level})
end
function Npc.getTurretLevel(self)
local addon = self:getOutfit().lookAddons
if addon == 0 then
return 1
end
return addon
end
function getWaveLevel()
return Game.getStorageValue(waveLevelGlobalStorage) or 0
end
function setWaveLevel(lvl)
Game.setStorageValue(waveLevelGlobalStorage, lvl)
end
function Player.getCoins(self)
return self:getStorageValue(coinStorage)
end
function Player.addCoins(self, amount)
self:setStorageValue(coinStorage, math.max(0, self:getStorageValue(coinStorage)) + amount)
end
dofile('data/libs/TWD/towerDefenseLib.lua')
function onModalWindow(player, modalWindowId, buttonId, choiceId)
if modalWindowId ~= 101 then -- Not our window
return false
elseif buttonId == 1 then -- Cancel
return false
end
local npc = targetTurret
local npcLvl = npc:getTurretLevel()
local table = turrets[npc:getOutfit().lookType].cfg[npcLvl]
if choiceId == 0 then
if player:getCoins() < table.upgradePrice then
player:sendCancelMessage("You don't have enough of coins.")
return false
end
npcLvl = npcLvl + 1
local setColor = table.colorId
npc:setOutfit({lookType = npc:getOutfit().lookType, lookHead = setColor , lookBody = setColor, lookLegs = setColor, lookFeet = setColor, lookAddons = npcLvl})
npc:getPosition():sendMagicEffect(math.random(CONST_ME_FIREWORK_YELLOW, CONST_ME_FIREWORK_BLUE))
player:addCoins(-table.upgradePrice)
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have total ".. player:getCoins() .." coins.")
targetTurret = nil
else
player:addCoins(table.sellPrice)
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have total ".. player:getCoins() .." coins.")
npc:say("+" ..table.sellPrice, TALKTYPE_MONSTER_SAY)
player:addCoins(table.sellPrice)
npc:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED)
npc:remove()
targetTurret = nil
end
return true
end
[/lua]
Lua Script Error: [Action Interface]
data/actions/scripts/twdHammer.lua:onUse
data/actions/scripts/twdHammer.lua:8: attempt to call method 'getTile' (a nil value)
stack traceback:
[C]: in function 'getTile'
data/actions/scripts/twdHammer.lua:8: in function <data/actions/scripts/twdHammer.lua:3>
Lua Script Error: [MoveEvents Interface]
data/movements/scripts/twdTile.lua:onStepIn
data/lib/compat/compat.lua:314: attempt to call global 'doTargetCombat' (a nil value)
stack traceback:
[C]: in function 'doTargetCombat'
data/lib/compat/compat.lua:314: in function 'doTargetCombatHealth'
data/movements/scripts/twdTile.lua:10: in function <data/movements/scripts/twdTile.lua:3>
[C]: in function 'teleportTo'
can someone help me with this?oh, i've been looking for something like this for a long time!
but i have a problem with setting in tfs 1.3
should a modal window open when the event starts?
when switching to tp, it teleports me to the room. after 30 seconds, 1 wave of mobs begins. when using a hammer gives an error.
after the wave passes, it gives the following error. (should mobs hit a wall?)C++:Lua Script Error: [Action Interface] data/actions/scripts/twdHammer.lua:onUse data/actions/scripts/twdHammer.lua:8: attempt to call method 'getTile' (a nil value) stack traceback: [C]: in function 'getTile' data/actions/scripts/twdHammer.lua:8: in function <data/actions/scripts/twdHammer.lua:3>
please help me with this. I really liked TD. but after the garena closed, there were few places to play.C++:Lua Script Error: [MoveEvents Interface] data/movements/scripts/twdTile.lua:onStepIn data/lib/compat/compat.lua:314: attempt to call global 'doTargetCombat' (a nil value) stack traceback: [C]: in function 'doTargetCombat' data/lib/compat/compat.lua:314: in function 'doTargetCombatHealth' data/movements/scripts/twdTile.lua:10: in function <data/movements/scripts/twdTile.lua:3> [C]: in function 'teleportTo'
Of course, there are other platforms with Warcraft 3, but there is only DotA.
thanks in advance, looking forward to help.
Post automatically merged:
View attachment 66702