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

vulkantsk

Супермодератор
Команда форума
21 Июн 2017
789
122
www.dotabuff.com
Проект
Roshan defense
Сегодня я решил поделиться с вами одной из самых крутых своих наработок, которая объеденяет большую часть всех гайдов на форуме.
Данная наработка будет полезна абсолютно всем новичкам и даже модерам с опытом.
С помошью данного шаблона вы сможете создать очень крутой херо дефенс (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:
Всем пока, всем удачи !

Ссылка на стим
Ссылка на гитхаб
 

HappyFeedFriends

Друзья CG
14 Авг 2017
538
30
Проект
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
789
122
www.dotabuff.com
Проект
Roshan defense
Ну так это свою логику писать надо, возьми задачу поменьше или корректней.
 
20 Дек 2016
873
150
Если есть возможность устроить это же через приказы , было бы весьма не плохо!)
Код:
        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
873
150
Скорее всего можно с помощью SpawnEntityFromTableSynchronous(string string_1, handle handle_2) и подобных (посмотри примеры на гитхабе). По идее в таблицу можно указать любой параметр, который можно задать в хаммере, надеясь, что у него такой же ключ, что и в хаммере. Но я не уверен в этом, нужно эксперементировать. Да и не понятно, зачем это вообще нужно, если приказы.
 

hima130

Новичок
28 Дек 2019
6
0
Проект
DotaCity50
А как сделать таким образом союзные волны крипов?
 
Реклама: