Урок Шаблон "Hero defense"

vulkantsk

Супермодератор
Команда форума
21 Июн 2017
1,137
196
www.dotabuff.com
Проект
Roshan defense
1663432731935.pngСегодня я решил поделиться с вами одной из самых крутых своих наработок, которая объеденяет большую часть всех гайдов на форуме.
Данная наработка будет полезна абсолютно всем новичкам и даже модерам с опытом.
С помошью данного шаблона вы сможете создать очень крутой херо дефенс (Moo Moo я жду тебя ;))
Вот собственно сама карта:
hero_defense_map.png


Особенности шаблона:
  • настройки мода: начальный уровень героя ,длительность возрождения и многое другое
  • система выпадения предметов
  • система лайновых крипов
  • система порталов
  • локализации русская/английская
  • возрождение нейтральных крипов
  • поведение юнитов AI

Система выпадения предметов:

  • файл: scripts/vscripts/item_drop
  • items - список предметов, которые могут выпасть
  • chance - шанс выпадения (если не определен, то равен 100%)
  • список юнитов из которых могут выпасть предметы ( если не определен, то выпадает с любого юнита)
  • duration - длительность жизни предмета на полу( если не определен, то предмет лежит бесконечно)
  • limit - лимит предметов - количество предметов, которые могут выпасть( если не определен, то количество не ограничено)

Система лайновых крипов
  • файл: scripts/vscripts/gamemode
  • reward gold - награда золота за прохождение волны
  • reward exp - награда опыта за прохождение волны
  • units - список юнитов, которые будут идти по линии
Возрождение нейтральных крипов
  • файл: scripts/vscripts/abilities/respawn
  • weak - возрождается на месте, где его убили через 5 секунд
  • strong - возрождается на месте, где появился
  • boss - возрождается на месте, где появился. После возрождения улучшается
Поведение юнитов
  • файл: scripts/vscripts/ai/...
  • поведение нейтрального босса 1/2/3 уровня
  • поведение лайнового босса
Надеюсь данный "урок" будет вам полезен, так как я вложил много времени и сил на его создание.
Может быть скоро мы увидим новых энтузиастов с горящими глазами, которые смогут создать годный Hero Defense (например MooMoo)
Ах да у меня там много мусора в файлах, было оченб сильно лень так что не обессудьте :cool:
Всем пока, всем удачи !

Ссылка на стим
Ссылка на гитхаб
 
Последнее редактирование:

HappyFeedFriends

Друзья CG
14 Авг 2017
540
32
Проект
Battle Heroes Arena
вау,супер, просто класс! Ставьте все лайки! В топ! Ваааау, это просто крутейбл
 

Kotokosat

Новичок
25 Мар 2020
4
0
Возьму вашу базу AI,спасибо,помогите пожалуйста в личных сообщениях с выбором героев.
 

Dangalor

Пользователь
11 Авг 2016
32
0
Всем привет !
Сделал по вашему примеру, все работает. Но нужно немного другое и тут загвоздка...
В целом затея такая после спавна в рандомной точке генериться энтити в луа и в неё идут мобы, после того как доходят нужно перенаправить их в новую рандомную точку
но они категорически отказываются следовать туда , игорируя unit:SetInitialGoalEntity( waypoint )
Код:
require( 'timer' )

if GameMode == nil then
    _G.GameMode = class({})
end


GameMode.current_units = {}
GameMode.line_interval = {}
GameMode.wave_number = 0

GameMode.wave_list = {
    [1]={reward_gold=1000,reward_exp=500,
            units={["npc_dota_creep_goodguys_melee_upgraded_mega"]=6}},
    [2]={reward_gold=5000,reward_exp=1000,
            units={["npc_dota_hero_slardar"]=2}},
    -- [3]={reward_gold=1000,reward_exp=2000,
    --         units={"npc_line_boss_1",["npc_line_creep_4"]=2}},
}

function Precache( context )
    --[[
        Precache things we know we'll use.  Possible file types include (but not limited to):
            PrecacheResource( "model", "*.vmdl", context )
            PrecacheResource( "soundfile", "*.vsndevts", context )
            PrecacheResource( "particle", "*.vpcf", context )
            PrecacheResource( "particle_folder", "particles/folder", context )
    ]]
end

-- Create the game mode when we activate
function Activate()
    GameRules.AddonTemplate = GameMode()
    GameRules.AddonTemplate:InitGameMode()
end

function GameMode:InitGameMode()
    print( "Template addon is loaded. GameMode:InitGameMode()" )
    ListenToGameEvent('game_rules_state_change', Dynamic_Wrap(self, 'OnGameRulesStateChange'), self)
    GameRules:GetGameModeEntity():SetThink( "OnThink", self, "GlobalThink", 2 )
    ListenToGameEvent('entity_killed', Dynamic_Wrap(self, 'OnEntityKilled'), self)
end

function GameMode:OnGameRulesStateChange()
    local newState = GameRules:State_Get()
    print("State "..newState)
    GameRules:SendCustomMessage("#State "..newState,0,0)
if newState == 7 then
    print("SPAAAAAAAAAAAAAAAAAAWWN ")
        GameMode:LineBossSpawner()
    end
    -- if newState == DOTA_GAMERULES_STATE_GAME_IN_PROGRESS then
    --     GameMode:LineBossSpawner()
    -- end
end

function GameMode:LineBossSpawner()
     self.wave_number = self.wave_number + 1   
    local current_boss = self.wave_list[self.wave_number]

    --if current_boss == nil then
    --    GameRules:SetGameWinner(DOTA_TEAM_GOODGUYS)
    --    return
    --end

    GameMode:SpawnLineUnits(self.wave_number)
end

function GameMode:SpawnLineUnits(index)
    local current_wave = self.wave_list[index]
    local flag = 1;
    if current_wave == nil then
    print( "Array of wawes index out of range")
        return
    end

    local point = Entities:FindByName( nil, "z1"):GetAbsOrigin()
    -- local POINTS = class({})
    -- for i=0,10 do
    --     -- POINTS.vectors[i]= Vector(RandomInt(-2000,2000),RandomInt(-2000,2000),RandomInt(0,0))
    --     -- POINTS[i] = Entities:CreateByClassname ("path_corner"):SetAbsOrigin(Vector(RandomInt(-2000,2000),RandomInt(-2000,2000),RandomInt(0,0)))
 --        -- print (POINTS[i]:GetAbsOrigin())
 --        print ("i = "..i)
    -- end
    
    local v = Vector(RandomInt(-2000,2000),RandomInt(-2000,2000),RandomInt(0,0))
    local v2 = Entities:CreateByClassname ("path_corner")
    v2:SetAbsOrigin(v)
    print (v2:GetAbsOrigin())


    local waypoint = v2 --Entities:FindByName( nil, "p1")
    local units = current_wave.units

    for key, value in pairs (units) do
        if type(key) == "string" then
            unit_count = value
            unit_name = key
            else
            unit_count =1
            unit_name = value
        end
                        -- print ("self.current_units[ent_index]")
        for i=1, unit_count do
            local unit = CreateUnitByName( unit_name , point + RandomVector( RandomFloat( 0, 200 ) ), true, nil, nil, DOTA_TEAM_BADGUYS )
            unit:SetInitialGoalEntity( waypoint )
            unit:MoveToPosition( v )
            unit.reward = true
            local ent_index = unit:entindex()
            -- table.insert(self.current_units, ent_index, unit)
            self.current_units[ent_index]= unit
-- local q1  = self.current_units[ent_index]:GetUnitName();
--                         print ("index "..ent_index)
--                         print (self.current_units[ent_index])
--                         print ( q1)
        end
    end

    -- тута будет какоенить  умное  зацикливание
    Timers:CreateTimer(15, function()
        GameRules:SendCustomMessage("#kanec ",0,0)
        local r = Vector(RandomInt(-2000,2000),RandomInt(-2000,2000),RandomInt(0,0))
        local r2 = Entities:CreateByClassname ("path_corner")
        r2:SetAbsOrigin(r)
        print (r2:GetAbsOrigin())
        local XX = FindUnitsInRadius(DOTA_TEAM_BADGUYS,v2:GetAbsOrigin(), nil, 350, DOTA_UNIT_TARGET_TEAM_FRIENDLY, DOTA_UNIT_TARGET_BASIC, 0, 0, false )
        if XX ~= nil then
            v2:Destroy()
            for k, unit in pairs(XX) do
                unit:SetInitialGoalEntity( r2 )               
                -- unit:Stop()
                -- unit:MoveToPosition( r )
                print ("unit name =  "..unit:GetUnitName())
            end
        end   
        GameRules:SendCustomMessage("#kanec2 ",0,0)
    end) 
end

-- Evaluate the state of the game
function GameMode:OnThink()
    if GameRules:State_Get() == DOTA_GAMERULES_STATE_GAME_IN_PROGRESS then
        --print( "Template addon script is running." )
    elseif GameRules:State_Get() >= DOTA_GAMERULES_STATE_POST_GAME then
        return nil
    end
    return 1
end

function GameMode:OnEntityKilled(keys)

    local unit = EntIndexToHScript(keys.entindex_killed)
    local unit_name = unit:GetUnitName()
    
    if unit_name == "npc_goodguys_fort" then
        GameRules:SetGameWinner(DOTA_TEAM_BADGUYS)       
    end

    if unit.reward then
        local ent_index = unit:entindex()
        
        self.current_units[ent_index] = nil
        local units = 0
        for key,value in pairs(self.current_units) do
            units = units + 1
        end

        if units == 0 then
            local current_wave = self.wave_list[self.wave_number]
            local reward_gold = current_wave.reward_gold
            local reward_exp = current_wave.reward_exp

            GiveGoldPlayers( reward_gold )
            GiveExperiencePlayers( reward_exp )
            GameMode:LineBossSpawner()
        end
    end
end

function GiveGoldPlayers( gold )
    for index=0 ,4 do
        if PlayerResource:HasSelectedHero(index) then
            local player = PlayerResource:GetPlayer(index)
            local hero = PlayerResource:GetSelectedHeroEntity(index)
            hero:ModifyGold(gold, false, 0)
            SendOverheadEventMessage( player, OVERHEAD_ALERT_GOLD, hero, gold, nil )
        end
    end
end


function GiveExperiencePlayers( experience )
    for index=0 ,4 do
        if PlayerResource:HasSelectedHero(index) then
            local player = PlayerResource:GetPlayer(index)
            local hero = PlayerResource:GetSelectedHeroEntity(index)
            hero:AddExperience(experience, 0, false, true )
        end
    end
end

Если есть возможность устроить это же через приказы , было бы весьма не плохо!)
Но почемуто нифига не работает )
 

vulkantsk

Супермодератор
Команда форума
21 Июн 2017
1,137
196
www.dotabuff.com
Проект
Roshan defense
Ну так это свою логику писать надо, возьми задачу поменьше или корректней.
 
20 Дек 2016
892
170
Если есть возможность устроить это же через приказы , было бы весьма не плохо!)
Код:
        ExecuteOrderFromTable({
            UnitIndex = hUnit:entindex(),
            OrderType = DOTA_UNIT_ORDER_MOVE_TO_POSITION,
            Position = vPos,
            Queue = 0
        })
Если в Queue поставить 1, то можно несколько раз подряд это через цикл заюзать, и юнит будет перемещаться между точками в указанном порядке. Но размер очереди ограничен.
Можешь попробовать вместо DOTA_UNIT_ORDER_MOVE_TO_POSITION использовать DOTA_UNIT_ORDER_PATROL, тогда по идее юнит вообще не остановится никогда.
 

UFO

Пользователь
2 Сен 2016
17
0
А может можно как то в lua next point задать ?
 
20 Дек 2016
892
170
Скорее всего можно с помощью SpawnEntityFromTableSynchronous(string string_1, handle handle_2) и подобных (посмотри примеры на гитхабе). По идее в таблицу можно указать любой параметр, который можно задать в хаммере, надеясь, что у него такой же ключ, что и в хаммере. Но я не уверен в этом, нужно эксперементировать. Да и не понятно, зачем это вообще нужно, если приказы.
 

lesssay[j]

Пользователь
28 Дек 2019
16
2
vk.com
Проект
Diretide SuperStar
А как сделать таким образом союзные волны крипов?
 

romanson

Пользователь
5 Фев 2020
33
3
Проект
Diablo_rpg
Сегодня я решил поделиться с вами одной из самых крутых своих наработок, которая объеденяет большую часть всех гайдов на форуме.
Данная наработка будет полезна абсолютно всем новичкам и даже модерам с опытом.
С помошью данного шаблона вы сможете создать очень крутой херо дефенс (Moo Moo я жду тебя ;))
Вот собственно сама карта:


Особенности шаблона:
  • настройки мода: начальный уровень героя ,длительность возрождения и многое другое
  • система выпадения предметов
  • система лайновых крипов
  • локализации русская/английская
  • возрождение нейтральных крипов
  • поведение юнитов AI

Система выпадения предметов:

  • файл: scripts/vscripts/item_drop
  • items - список предметов, которые могут выпасть
  • chance - шанс выпадения (если не определен, то равен 100%)
  • список юнитов из которых могут выпасть предметы ( если не определен, то выпадает с любого юнита)
  • duration - длительность жизни предмета на полу( если не определен, то предмет лежит бесконечно)
  • limit - лимит предметов - количество предметов, которые могут выпасть( если не определен, то количество не ограничено)

Система лайновых крипов
  • файл: scripts/vscripts/gamemode
  • reward gold - награда золота за прохождение волны
  • reward exp - награда опыта за прохождение волны
  • units - список юнитов, которые будут идти по линии
Возрождение нейтральных крипов
  • файл: scripts/vscripts/abilities/respawn
  • weak - возрождается на месте, где его убили через 5 секунд
  • strong - возрождается на месте, где появился
  • boss - возрождается на месте, где появился. После возрождения улучшается
Поведение юнитов
  • файл: scripts/vscripts/ai/...
  • поведение нейтрального босса 1/2/3 уровня
  • поведение лайнового босса
Надеюсь данный "урок" будет вам полезен, так как я вложил много времени и сил на его создание.
Может быть скоро мы увидим новых энтузиастов с горящими глазами, которые смогут создать годный Hero Defense (например MooMoo)
Ах да у меня там много мусора в файлах, было оченб сильно лень так что не обессудьте :cool:
Всем пока, всем удачи !

Ссылка на стим
Ссылка на гитхаб
Что с гитхабом? почини ссылку плиз))
 

Julian Slink

Пользователь
11 Апр 2021
13
2
Запускаю тест карты и постоянно одни и те же ошибки, в чём причина?
error.png
500-525 строки
Lua:
function GameSettings:OnPlayerLevelUp(keys)
    print ('[BAREBONES] OnPlayerLevelUp')
    DeepPrintTable(keys)

    local hero = PlayerResource:GetSelectedHeroEntity(keys.player_id)
    local level = keys.level
    local ability_point = hero:GetAbilityPoints()
    print(level)
    if hero and level then
        local no_points_levels = {
        [17] = 1,
        [19] = 1,
        [21] = 1,
        [22] = 1,
        [23] = 1,
        [24] = 1,
        }

        if no_points_levels[level] or level >= 30 then
            hero:SetAbilityPoints(ability_point + 1)
        end
    end
end
588-625 строка

Lua:
function GameSettings:OnNPCSpawned(keys)
--    print("[BAREBONES] NPC Spawned")
--    DeepPrintTable(keys)
    local npc = EntIndexToHScript(keys.entindex)
    local name = npc:GetUnitName()
   
    if npc:IsRealHero() and npc.bFirstSpawned == nil then
--        GameSettings:OnHeroInGame(npc)          
        npc.bFirstSpawned = true
        local playerID = npc:GetPlayerID()
        local steamID = PlayerResource:GetSteamAccountID(playerID)

        if FirstSpawned == nil then
            FirstSpawned = {}
        end
       
        if not FirstSpawned[playerID] then

            FirstSpawned[playerID] = true
            while npc:GetLevel() < HERO_START_LEVEL do
                npc:AddExperience(50, 0, true, true)
            end
        end
    end  
    if npc:IsTempestDouble() or npc:IsIllusion() then
        local owner = npc:GetPlayerOwner():GetAssignedHero()
        npc:SetTeam(owner:GetTeam())
        for _, modifier in pairs( owner:FindAllModifiers() ) do
            local stacks = modifier:GetStackCount()
            local modifier_name = modifier:GetName()

            if stacks > 0 then
                local modifier = npc:AddNewModifier(owner, nil, modifier_name, {})
                modifier:SetStackCount(stacks)
            end
        end
    end
end
 
Последнее редактирование модератором:

vulkantsk

Супермодератор
Команда форума
21 Июн 2017
1,137
196
www.dotabuff.com
Проект
Roshan defense
Запускаю тест карты и постоянно одни и те же ошибки, в чём причина?
500-525 строки
Lua:
function GameSettings:OnPlayerLevelUp(keys)
    print ('[BAREBONES] OnPlayerLevelUp')
    DeepPrintTable(keys)

    local hero = PlayerResource:GetSelectedHeroEntity(keys.player_id)
    local level = keys.level
    local ability_point = hero:GetAbilityPoints()
    print(level)
    if hero and level then
        local no_points_levels = {
        [17] = 1,
        [19] = 1,
        [21] = 1,
        [22] = 1,
        [23] = 1,
        [24] = 1,
        }

        if no_points_levels[level] or level >= 30 then
            hero:SetAbilityPoints(ability_point + 1)
        end
    end
end
588-625 строка

Lua:
function GameSettings:OnNPCSpawned(keys)
--    print("[BAREBONES] NPC Spawned")
--    DeepPrintTable(keys)
    local npc = EntIndexToHScript(keys.entindex)
    local name = npc:GetUnitName()
 
    if npc:IsRealHero() and npc.bFirstSpawned == nil then
--        GameSettings:OnHeroInGame(npc)        
        npc.bFirstSpawned = true
        local playerID = npc:GetPlayerID()
        local steamID = PlayerResource:GetSteamAccountID(playerID)

        if FirstSpawned == nil then
            FirstSpawned = {}
        end
     
        if not FirstSpawned[playerID] then

            FirstSpawned[playerID] = true
            while npc:GetLevel() < HERO_START_LEVEL do
                npc:AddExperience(50, 0, true, true)
            end
        end
    end
    if npc:IsTempestDouble() or npc:IsIllusion() then
        local owner = npc:GetPlayerOwner():GetAssignedHero()
        npc:SetTeam(owner:GetTeam())
        for _, modifier in pairs( owner:FindAllModifiers() ) do
            local stacks = modifier:GetStackCount()
            local modifier_name = modifier:GetName()

            if stacks > 0 then
                local modifier = npc:AddNewModifier(owner, nil, modifier_name, {})
                modifier:SetStackCount(stacks)
            end
        end
    end
end
Чтобы не засорять место, под большие блоки кода используй спойлер.

А еще лучше отмечай каким-то цветом или шрифтом, в каком месте начинается ошибка )
Да, эти ошибки есть. Насколько я знаю они не мешают работе, в любом случае на данный момент я не знаю как их исправить.
 

Julian Slink

Пользователь
11 Апр 2021
13
2
Спасибо, ещё такой вопрос, как принудительно запустить новую волну спустя N-время?
Вижу есть код GameMode.line_interval, а как его использовать ещё не понял
 

Julian Slink

Пользователь
11 Апр 2021
13
2
  • Вооу
Реакции: vulkantsk

Julian Slink

Пользователь
11 Апр 2021
13
2
Так и не понял половину функционала кода
Начал писать с 0

И тем не менее, спасибо за шаблон, в котором можно посмотреть принцип работы тех или иных функций
 
  • Нравится
Реакции: vulkantsk

senkasa

Новичок
22 Июн 2023
7
0
как зделать раунды и что бы в конце раунда тпхело на спавны
 
Реклама: