, Гильдия «Черамор»

Upgrade Build

» опубликован
» Способ реализации: Zinc
» Тип: Наработка

Upgrade Build

MUI: да
Импорт: нет
Утечки: нет
Требования: JNGP
Описание: Наработка, позволяющая улучшать здания пристраивая их рядом с основным.
  • Настройка полностью в РО
  • Расчитана на здания, с картой путей 4х4

Скриншот

Технические подробности

» Перенос в свою карту
Войска
  • 'ubsl' Upgrade Build (selecter)
  • 'ubwk' Upgrade Build (checker)
Способности
  • 'ub32' Upgrade Build 32
Триггеры
  • UpgradeBuild
» Настройки
constant integer SELECTER_ID = 'ubsl';
constant integer CHEKER_ID = 'ubwk';
constant integer ABILITY_32 = 'ub32';
constant string ATTACH_NAME = "Abilities\\Spells\\Other\\Aneu\\AneuCaster.mdl";
constant string ATTACH_POINT = "gold";
  • Указываете в поле Технологии - улучшается до (uupt) необходимые здания.
  • Если указанное здание имеет способность ABILITY_32, то сработает наработка, если нет, произойдёт стандартное улучшение.
» Код заклинания
// !nocjass
native GetUnitGoldCost takes integer unitid returns integer
native GetUnitWoodCost takes integer unitid returns integer

//! zinc
library UpgradeBuild {
    constant integer SELECTER_ID = 'ubsl';
    constant integer CHEKER_ID = 'ubwk';
    constant integer ABILITY_32 = 'ub32';
    constant string ATTACH_NAME = "Abilities\\Spells\\Other\\Aneu\\AneuCaster.mdl";
    constant string ATTACH_POINT = "gold";
    
    /*
    *
    *
    */
    unit CHECKER;
    constant integer W = 128;
    constant integer X[];
    constant integer Y[];
    group SELECTERS[];
    effect ATTACH_BUILD[];
    
    hashtable HT = InitHashtable();
    
    function upgradeCancel(unit target){
        timer t = CreateTimer();
        integer pk = GetHandleId(t);
        player p = GetOwningPlayer(target);
        SaveUnitHandle(HT, pk, 0, target);
        SaveInteger(HT, pk, 0, GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD));
        SaveInteger(HT, pk, 1, GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER));
        TimerStart(t, 0, false, function(){
            timer t = GetExpiredTimer();
            integer pk = GetHandleId(t);
            unit u = LoadUnitHandle(HT, pk, 0);
            player p = GetOwningPlayer(u);
            IssueImmediateOrderById(u, 851976);
            SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, LoadInteger(HT, pk, 0));
            SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, LoadInteger(HT, pk, 1));
            u = null;
            FlushChildHashtable(HT, pk);
            PauseTimer(t); DestroyTimer(t); t = null;
        });
        t = null;
    }
    
    function checkUpgrade(integer order) -> boolean {
        boolean abi;
        unit u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), order, 0, 0, 0);
        if (u == null){ return false; }
        abi = GetUnitAbilityLevel(u, ABILITY_32) > 0;
        ClearTextMessages();
        RemoveUnit(u); u = null;
        return abi;
    }
    
    function checkBuild(real x, real y) -> boolean {
        boolean place;
        SetUnitX(CHECKER, x - W);
        SetUnitY(CHECKER, y);
        place = IssueBuildOrderById(CHECKER, SELECTER_ID, x, y);
        IssueImmediateOrderById(CHECKER, 851972 /* stop */);
        return place;
    }
    
    function clearSelecters(player p){
        integer pid = GetPlayerId(p);
        unit u;
        if (ATTACH_BUILD[pid] != null){
            DestroyEffect(ATTACH_BUILD[pid]);
            ATTACH_BUILD[pid] = null;
        }
        
        while(true){
            u = FirstOfGroup(SELECTERS[pid]);
            if (u == null) { break; }
            GroupRemoveUnit(SELECTERS[pid], u);
            FlushChildHashtable(HT, GetHandleId(u));
            RemoveUnit(u);
        }
    }
    
    
    function onInit(){
        integer i;
        trigger tOrder = CreateTrigger();
        trigger tSelect = CreateTrigger();

        CHECKER = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'ubwk', 0, 0, 0);
        X[0] = W; Y[0] = 0;
        X[1] = W; Y[1] = W;
        X[2] = 0; Y[2] = W;
        X[3] = W; Y[3] = -W;
        X[4] = 0; Y[4] = -W;
        X[5] = -W; Y[5] = -W;
        X[6] = -W; Y[6] = 0;
        X[7] = -W; Y[7] = W;
        
        for (0 <= i < bj_MAX_PLAYER_SLOTS){
            SELECTERS[i] = CreateGroup();
            SetPlayerAbilityAvailable(Player(i), ABILITY_32, false);
            TriggerRegisterPlayerUnitEvent(tOrder, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null);
            TriggerRegisterPlayerUnitEvent(tSelect, Player(i), EVENT_PLAYER_UNIT_SELECTED, null);
        }
        
        // order
        TriggerAddCondition(tOrder, Filter(function() -> boolean {
            return IsUnitType(GetTriggerUnit(), UNIT_TYPE_STRUCTURE) && GetIssuedOrderId() > 10000000;
        }));
        TriggerAddAction(tOrder, function(){
            unit u, caster = GetTriggerUnit();
            integer order = GetIssuedOrderId();
            real xb, x = GetUnitX(caster);
            real yb, y = GetUnitY(caster);
            player p = GetOwningPlayer(caster);
            integer pid = GetPlayerId(p);
            integer i;
            
            clearSelecters(p);
            if (checkUpgrade(order)){
                upgradeCancel(caster);
                ATTACH_BUILD[pid] = AddSpecialEffectTarget(ATTACH_NAME, caster, ATTACH_POINT);
                
                for(0 <= i <= 7){
                    xb = x + X[i];
                    yb = y + Y[i];
                    if (checkBuild(xb, yb)){
                        u = CreateUnit(p, SELECTER_ID, xb, yb , 90);
                        GroupAddUnit(SELECTERS[pid], u);
                        SaveInteger(HT, GetHandleId(u), 0, order);
                    }
                }
            }
            
            u = null;
        });
        
        // select
        TriggerAddAction(tSelect, function(){
            unit u, target = GetTriggerUnit();
            integer uid, pk = GetHandleId(target);
            player p = GetOwningPlayer(target);
            if (GetUnitTypeId(target) == SELECTER_ID){
                RemoveUnit(target);                
                u = CreateUnit(p, LoadInteger(HT, pk, 0), GetUnitX(target), GetUnitY(target), bj_UNIT_FACING);
                uid = GetUnitTypeId(u);
                SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) - GetUnitGoldCost(uid));
                SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER) - GetUnitWoodCost(uid));
                if (GetLocalPlayer() == p){
                    ClearSelection();
                    SelectUnit(u, true);
                }
                FlushChildHashtable(HT, pk);
            }
            clearSelecters(p);
            target = null;
            u = null;
        });
        
        
        tOrder = null;
        tSelect = null;
    }
}
//! endzinc
// !endnocjass


Просмотров: 876

» Лучшие комментарии


KaneThaumaturge #1 - 7 месяцев назад 2
Сразу вспомнил Kingdoms and Castles. Не смотрел в код, но выглядит круто, ставлю +.
Квадратный круг выбора, неожиданно, прикольно смотрится.
NazarPunk #2 - 7 месяцев назад 5
Квадратный круг выбора, неожиданно, прикольно смотрится.
Не нашёл способа лучше показать карту путей)
Clamp #3 - 7 месяцев назад 0
Когда-то делал карту по мобильной ява-игре "Эмиссары", которая отдалённо копировала цивилизацию и там была довольно похожая система постройки города.
Так вот к чему это я... Карту я так и не доделал из за того, что если рядом был нестроибельный тайл, возникало неопределённое поведение. Сейчас я бы решил вопрос фиксированными локациями, но тогда очень хотелось позволить селиться куда угодно.
Как у тебя решается такая проблема?
NazarPunk #4 - 7 месяцев назад (отредактировано ) 1
Как у тебя решается такая проблема?
Если имется ввиду проверка строительства, то через IssueBuildOrderById от даммика.
    function checkBuild(real x, real y) -> boolean {
        boolean place;
        SetUnitX(CHECKER, x - W);
        SetUnitY(CHECKER, y);
        place = IssueBuildOrderById(CHECKER, SELECTER_ID, x, y);
        IssueImmediateOrderById(CHECKER, 851972 /* stop */);
        return place;
    }

На скриншоте видно, что даже юниты мешают постройке.
Clamp #5 - 7 месяцев назад 0
NazarPunk, хорошее решение.
Настоятельно рекоммендую переименовать невнятную константу "W" в "BUILDING_WIDTH" и/или дать ей зависимость от фактической ширины клетки строительства и ширины здания, чтобы можно было в одно изменение значения адаптировать систему к другой сетке зданий.
NazarPunk #6 - 7 месяцев назад 0
Настоятельно рекоммендую переименовать невнятную константу "W"
У неё короткое название для краткости записи
X[0] = W; Y[0] = 0;
X[1] = W; Y[1] = W;
X[2] = 0; Y[2] = W;
X[3] = W; Y[3] = -W;
X[4] = 0; Y[4] = -W;
X[5] = -W; Y[5] = -W;
X[6] = -W; Y[6] = 0;
X[7] = -W; Y[7] = W;
Если понадобится адаптирование под разные размеры, то она станет аргументом функции, а значение будет получаться динамически. Если б можно динамически получить размер карты путей, то переделал бы.
Steal nerves #7 - 7 месяцев назад (отредактировано ) 3
вот эта классная система =))
можно цивилизацию и героев наделать
NazarPunk #8 - 7 месяцев назад 0
можно цивилизацию и героев наделать
Так делайте, а если понадобятся интересные в реализации системы, пишите)
PT153 #9 - 7 месяцев назад 1
Видел похожую тему в одной карте, только там это делалось с помощью виспов.
Clamp #10 - 7 месяцев назад 5
У неё короткое название для краткости записи
"Догадайся сам"?
Краткость записи куда как менее важный фактор в сравнении с понятностью кода
NazarPunk #11 - 7 месяцев назад 0
Краткость записи куда как менее важный фактор в сравнении с понятностью кода
Если буду добавлять новые размеры путей, переделаю)
SomnusUltima #12 - 7 месяцев назад 0
классная наработка, можно много всяких интересных тем придумать с ней
Артём9 #13 - 6 месяцев назад 0
Clamp:
Когда-то делал карту по мобильной ява-игре "Эмиссары", которая отдалённо копировала цивилизацию и там была довольно похожая система постройки города.
Так вот к чему это я... Карту я так и не доделал из за того, что если рядом был нестроибельный тайл, возникало неопределённое поведение. Сейчас я бы решил вопрос фиксированными локациями, но тогда очень хотелось позволить селиться куда угодно.
Как у тебя решается такая проблема?
Эмиссары... Revival 2 может? Там тоде эмиссар был как глава государства и когда его убивали ты проигрывал.
Clamp #14 - 6 месяцев назад 0
Артём9, уже не помню, вроде бы локализированная версия была именно с таким названием. Но да, это она.