XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Академия: форум для вопросов
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

Ответ
 
DioD

offline
Опыт: 45,134
Активность:
Решил на днях запилить систему которая позволит носить спеллы с карты на карту...
Сабж прост, очень прост, указатели на то, что делает спелл, хранятся в самом спелле, вообще такие системы уже были (5 или 6 раз), просто решил написать с нуля, никуда не подглядывая, а потом запостить на форуме.
Постить на форуме не цель, так что качество кода не супир, асци арта и табличек не будет.
Нормально эта система реализуется через хеш таблицу, но мне так не понравилось, хотелось хардкора, там из методов будет ясно как реализовать напрямую.
Представленный ниже метод выявляет айдишник переданного ему чара, ничего сложного и внезапного, такие методы есть в любой системе сейва через коды.
    string  SET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
function CharID takes string S returns integer
    local integer I = 0
    loop

        if S == SubString(SET,I,I+1) then
            return I
        endif
    
        if I >= 25 then
            return -1
        endif
        
        set I = I + 1
    endloop

    return -1
endfunction
Данный метод считает хеш строки, используя хеш таблицу это можно сделать вызовом StringHash в одну строку, производительность нативки существенно выше.
Основа метода кусок линейного генератора случайных чисел, это позволило добится иллюзии нормального распределения выходных значений. (на самом деле это не так и значения взяты с потолка)
Алгоритм рассчитан на 15 коллизий на каждый хеш, колиззии будут.
function SeqID takes string S returns integer

    local integer Lenght        = StringLength(S)-1
    local integer CurrentID     = 0
    local integer Loop          = 0
    local integer InternalLoop  = 0
    local integer Output        = 0
    
    if Lenght > 11 then
        return -1
    endif
    
    loop
        set CurrentID = CharID(SubString(S,Loop,Loop+1))
        if CurrentID == -1 then
            return -1
        endif

        set InternalLoop = Loop
        
            loop
                set CurrentID = CurrentID * 17 + 1
                exitwhen InternalLoop == 0
                set InternalLoop = InternalLoop -1
            endloop

        set Output = Output + CurrentID
        exitwhen Loop == Lenght
        set Loop = Loop + 1
    endloop
    return ModuloInteger(Output,512)
endfunction
Это уже код самой системы, резолюция колиззий крайне проста, недописал из за того что лень, нулевой индекс это счётчик, каждый раз при хеш колизии мы его увеличиваем и записываем наши данные в получившийся слот, ограничение 15 колизий.
При доступе к хешу мы сверяем значения учитывая данные из raw_id и находим именно то что нам надо.
Между прочим именно так сделано в ванильной реализации хеш таблиц на яве, да и в принципе сделать иначе невозможно.
function spellbus_add takes string S, code C returns boolean
    local integer TEST = SeqID(S)
    
    if hash_link[TEST] != 0 then
        //hash collision resolution code not yet implemented
        //it expected to have up to 15 hash collisions per each ID without any issues
        return false
    endif
    
    set raw_id[TEST]        = S
    set linked_object[TEST] = Condition(C)
    return true
endfunction
Основная логика, это единственный триггер который реагирует на выполнение способностей, логика кода крайне проста, если абилка помечена грязной мы не делаем ничего, если метки нет, проверяем есть ли на такую абилку регистрация.
function Trig_spellbus_Actions takes nothing returns nothing
    
    local integer ID = 0
    local triggercondition F

    if hash_link[GetSpellAbilityId()-'A000'] == -1 then
        return
    endif
    
    if hash_link[GetSpellAbilityId()-'A000'] == 0 then
        set ID = SeqID(GetAbilityEffectById(GetSpellAbilityId(),EFFECT_TYPE_SPECIAL, 0))
        if ID == -1 then
            set hash_link[GetSpellAbilityId()-'A000'] = -1
            return
        endif
        if linked_object[ID] != null then
            set hash_link[GetSpellAbilityId()-'A000'] = ID
        else
            set hash_link[GetSpellAbilityId()-'A000'] = -1
            return
        endif
    endif
    
    set F = TriggerAddCondition(execf,linked_object[hash_link[GetSpellAbilityId()-'A000']])
    call TriggerEvaluate(execf)
    call TriggerRemoveCondition(execf,F)
endfunction
"Нормальный" код на основе хеш таблицы и без развлекухи с реализацией того что уже есть будет чуточку позже.
Дискас.
DioD добавил:
А теперь тотжесамый код написанный на базе встроенной хеш таблицы:
globals
    hashtable HASH = InitHashtable()
    trigger   EXEC = CreateTrigger()
    integer   HC_SPELLBUS_RAW = 146
    integer   HC_SPELLBUS_IDS = 147
    
    conditionfunc   array SPELLS
    integer           SPELLSLINK = 0
endglobals

function RegisterSpell takes string Name, code Method returns nothing
    set SPELLSLINK = SPELLSLINK + 1
    set SPELLS[SPELLSLINK] = Condition(Method)
    call SaveInteger(HASH,HC_SPELLBUS_RAW,StringHash(Name),SPELLSLINK)
endfunction

function Trig_spellbus_Actions takes nothing returns nothing
    
    local integer ID = LoadInteger(HASH,HC_SPELLBUS_IDS,GetSpellAbilityId())
    if ID == -1 then
        return
    endif
    
    if ID == 0 then
        set ID = LoadInteger(HASH,HC_SPELLBUS_RAW,StringHash(GetAbilityEffectById(GetSpellAbilityId(),EFFECT_TYPE_SPE​CIAL, 0)))
        if ID == 0 then
            call SaveInteger(HASH,HC_SPELLBUS_IDS,GetSpellAbilityId(),-1)
            return
        else
            call SaveInteger(HASH,HC_SPELLBUS_IDS,GetSpellAbilityId(),ID)
        endif
    endif
    
    call TriggerAddCondition(EXEC,SPELLS[ID])
    call TriggerEvaluate(EXEC)
    call TriggerClearConditions(EXEC)
endfunction

function firebolt takes nothing returns boolean
    call DisplayTextToPlayer(Player(0),0,0,"Firebolt!")
    return false
endfunction

//===========================================================================
function InitTrig_spellbus takes nothing returns nothing
    set gg_trg_spellbus = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_spellbus, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( gg_trg_spellbus, function Trig_spellbus_Actions )
    
    call RegisterSpell("FIREBALL",function firebolt)
    
endfunction
Старый 28.08.2013, 16:59
adic3x

offline
Опыт: 108,439
Активность:
Черт, я конечно понимаю, что это - пример, но даже его смысл я не понял. Если первый код - показательно саркастический, примером чего является второй? Изобретения велосипеда?
Если я правильно понял цель системы (надеюсь), то в cJass я добавлял фишку:
callback onUnitSpellCast ('A000') { // Может быть макроопределение (define), константа, переменная, даже функция
    BJDebugMsg ("A000");
}
У меня кстати вопрос, может немного не по теме. Была такая карта - myDota. Ее делала одна не безызвестная личность. Потом была другая личность, Орлята, которая использовала наработки (именуемые движком) из первой карте в своей карте. Я тогда был маленьким, и кроме оскорбительного обращения в начале кода обеих карт мало что понял. Хотя речь шла о "крутости", "движке" и "препроцессоре".
Известно-ли что-то ДиоДу об этом всем? Интересуют технические подробности.
Старый 28.08.2013, 20:43
Bornikkeny
Silenced by Bornikkeny
offline
Опыт: 24,410
Активность:
ADOLF, мне вот тоже стало очень интересно, но боюсь, что из-за крайне малого количества серого вещества в моей черепной коробке мне не суждено понять смысл темы :-[
Старый 28.08.2013, 21:29
Anufis

offline
Опыт: 6,290
Активность:
Цитата:
Сообщение от Bornikkeny
мне не суждено понять смысл темы

Цитата:
Сообщение от DioD
Решил на днях запилить систему которая позволит носить спеллы с карты на карту...

Цитата:
Сообщение от DioD
систему которая позволит носить спеллы с карты на карту...
Старый 28.08.2013, 21:52
DioD

offline
Опыт: 45,134
Активность:
заметь, айдишник для определения того, что будет выполнено, не используется, это позволяет просто скопировать код и абилку и она будет работать, какой бы айдишник у неё ни был, в этом и есть смысл.
Старый 29.08.2013, 07:30
adic3x

offline
Опыт: 108,439
Активность:
Я не вижу сложности в правке равкода, если он удобно вынесен в константы например. Другой вопрос, что как минимум надо исправить данные о уроне, уровнях и т. д. - если мы говорим о реальном переносе в другую карту. И более того, есть много вещей, которые также должны быть учтены: а именно коллизии с другими способностями и системами. Например снятие негативных бафов. Или банальное движение юнита (если, например его двигают одновременно две способности). Когда я писал cJass я задумывался об этих проблемах и видел выход в отдельной библиотеке, входящей в стандартную поставку. Но реализовано это не было.
Старый 29.08.2013, 10:01
DioD

offline
Опыт: 45,134
Активность:
если так думать, то вообще жизнь бессмысленна, вы хоть в лепёшку расшибитесь, если в карте конфликтующие системы или взаимоисключающие механизмы, просто так скопировать будет нельзя.
я же предлагаю систему которая полностью позволяет отказатся от правки кода, все данные можно прописывать в саму способность, намёк на мудоту и гейм верный, РС делает именно так, достаточно удобно выходит, не требуется вносить никаких изменений в код, всё работает через РО.
Старый 30.08.2013, 09:05
adic3x

offline
Опыт: 108,439
Активность:
Я, что-бы так не соврать - году в 2008 или 2009 для морлоков делал так:
function SPL_SpellRun takes nothing returns nothing
    local integer i=GetSpellAbilityId()
    local unit u=GetTriggerUnit()
    
    // 'C000'
    if i >= 0x43000000 and i <= 0x43ffffff then
        call ExecuteFunc("s" + I2S(i))
    endif
    
    set u = null
endfunction

function s1127231541 takes nothing returns nothing
    // ...
endfunction
В таком случае - можно действительно использовать только OE и копирование кода.
намёк на мудоту и гейм верный, РС делает именно так, достаточно удобно выходит, не требуется вносить никаких изменений в код, всё работает через РО
А увидеть это где-то реально?
Старый 30.08.2013, 10:52
DioD

offline
Опыт: 45,134
Активность:
к сожалению нет, если демонстрацию, то без особых проблем, я запилю простенький пример (он будет не простенький на самом деле) на днях сделаю, та идёт в это поле абилки строка в которой шифруются все параметры спелла, в сам спелл идёт битмаск который расшифровывает поле.

редактирование свойств идёт в отдельной проге которая представляет данные в понятном человеку виде, после эта програ пишет в поля СЛК таблиц эти данные, проги нет на руках, если только написать с нуля, но это долго.
Старый 30.08.2013, 11:58
adic3x

offline
Опыт: 108,439
Активность:
Мне скорее просто интересно, как это все работало и было ли это настолько круто, как преподавалась тогда. Практического смысла это не имеет.
та идёт в это поле абилки строка в которой шифруются все параметры спелла
Я, к слову, сразу подумал, что в системе в первом посте вполне можно было-бы писать название функции, что бы по ней сразу делать Execute. Избавились бы от необходимости регистрировать способность, хотя в целом такой подход неверен.
К слову, мой подход был немного другим. Когда я проектировал cJass, на позднем этапе была идея дать возможность генерировать объекты из кода, что-бы в коде можно было описать способность, а также все дополнительные способности, юниты, может даже импорт. В таком случае, при копировании кода все-бы создавалось автоматически, вкупе с общей библиотекой со многими "корректными" функциями это действительно давало бы простоту переноса способности с карту на карту. К сожалению реализовано это было не полностью.
#include "lib//MySuperSpell.j" (id = 'A000', manacost = 50)
Примерно так это должно было выглядеть.
Старый 30.08.2013, 13:12
DioD

offline
Опыт: 45,134
Активность:
это есть в дефолтном vjass только не очень хорошо документировано...
Старый 30.08.2013, 15:43
adic3x

offline
Опыт: 108,439
Активность:
это есть в дефолтном vjass только не очень хорошо документировано...
Да, кажется есть. Беда в том, что там весьма убогие макросы, да и не уверен я, что их можно скомбинировать с этим средством создания объектов.
К слову, я считаю не совсем правильным шифровать данные о способностях в чудо-строке редактора объектов. Использование констант, которые как правило описывают характеристики спелла в начале вполне годный и удобный вариант, который легко правиться и не дает каких-либо ограничений.
Старый 30.08.2013, 15:50
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 22:22.