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

StringFunctions

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

Набор функций для работы со строками

MUI: да
Импорт: нет
Утечки: нет
Требования: JNGP

Скриншоты

Установка

  • Скопировать триггер StringFunctions

Список функций

// Выводим сообщения
MessageTimed(string str, real time)
Message(string str)
MessageForPlayerTimed(player p, string str, real time)
MessageForPlayer(player p, string str)

// Очищаем строку сообщения
ClearTextMessagesForPlayer(player p)

// Получаем имя игрока
GetPlayerColorString(player p) -> string
GetPlayerNameColored(player p)  -> string

// Обрезаем крайние символы
LTrim(string str, string found) -> string
RTrim(string str, string found) -> string
Trim(string str, string found) -> string
// Примеры
LTrim("---T-r-i-m---", "-"); // T-r-i-m---
RTrim("---T-r-i-m---", "-"); // ---T-r-i-m
Trim("---T-r-i-m---", "-"); // T-r-i-m

// Конвертируем boolean в строку
B2S(boolean b) -> string
// Примеры
B2S(true); // true
B2S(!true); // false

// Превращаем строку в равкод
S2RAW(string ObjectId) -> integer
// Пример
S2RAW("hfoo"); // 1751543663
    
// Превращаем равкод в строку
RAW2S(integer ObjectId) -> string
// Пример
RAW2S(1751543663); // hfoo

// Заменяем подстроку
StringReplaceCounted(string str, string found, string replace, integer count) -> string
StringReplace(string str, string found, string replace) -> string
// Примеры
StringReplaceCounted("old old old old old", "new", 2); // new new old old old
StringReplaceCounted("old old old old old", "new", -2); // old old old new new
StringReplace("old old old old old", "new"); // new new new new new

// Склоняем строку в зависимости от числа
Declension(integer number, string dec1, string dec4, string dec5);
/* Описание
number - число, от которого склонять
dec1 - вариант склонения для числа 1, например "предмет"
dec4 - вариант склонения для числа 4, например "предмета"
dec5 - вариант склонения для числа 5, например "предметов"
*/
// Пример
Declension(100500, "предмет", "предмета", "предметов") // предметов

// Склоняем строку в зависимости от числа с заменой подстроки и учётом нуля
Declenser(integer number, string found, string dec0, string dec1, string dec4, string dec5) -> string
/* Описание
number - число, от которого склонять
found - подстрока, которая будет заменена на number
dec0 - вариант строки для number == 0, например "Рюкзак пуст"
dec1 - вариант склонения для числа 1, например "В рюкзаке %count% предмет"
dec4 - вариант склонения для числа 4, например "В рюкзаке %count% предмета"
dec5 - вариант склонения для числа 5, например "В рюкзаке %count% предметов"
*/
// Пример
Declenser(
	100500,
	"%count%",
	"Рюкзак пуст", 
	"В рюкзаке %count% предмет",
	"В рюкзаке %count% предмета",
	"В рюкзаке %count% предметов"
); // В рюкзаке 100500 предметов

Примеры использования

» Unit
//! zinc
library Unit requires StringFunctions {
    constant string SelectUnitHelp = "Чтобы узнать равкод |cffffff00юнита|r, просто выберите его.";
    constant string AddUnitCommand = "-unit";
    constant string AddUnitMessage = "Игрок %player-name% выбрал юнита: %unit-name%. %selected-count%.";
    constant string AddUnitHelp = "Чтобы создать юнита наберите |cffffff00" + AddUnitCommand + " |cff909090####|r.";
    constant string AddUnitEfect = "Objects\\Spawnmodels\\Human\\HCancelDeath\\HCancelDeath.mdl";
    constant string AddUnitError = "|cffff0000Ошибка!|r Невозможно создать юнита |cffffff00%error%|r.";
    
    public {
        function GetUnitNameColored(unit u) -> string {
            return "|cffffff00" + GetUnitName(u) + " |cff909090(" + RAW2S(GetUnitTypeId(u)) + ")|r";
        }
    }
    
    function onInit(){
        integer i;
        trigger t;
        Message(AddUnitHelp);
        Message(SelectUnitHelp);
        
        // Выбор юнита
        t = CreateTrigger();
        for(0 <= i < bj_MAX_PLAYER_SLOTS){
            TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SELECTED, null);
        }
        TriggerAddAction(t, function(){
            group g = CreateGroup();
            player p = GetTriggerPlayer();
            unit u;
            integer count  = 0;
            string s;
            SyncSelections();
            GroupEnumUnitsSelected(g, p, null);
            while (true){
                u = FirstOfGroup(g);
                if (u == null) { break; }
                count = count + 1;
                GroupRemoveUnit(g, u);
            }
            s = StringReplace(
                AddUnitMessage,
                "%player-name%",
                GetPlayerNameColored(p)
            );
            s = StringReplace(
                s,
                "%unit-name%",
                GetUnitNameColored(GetTriggerUnit())
            );
            s = StringReplace(
                s,
                "%selected-count%",
                Declenser(
                    count,
                    "%count%",
                    "Юнитов не выбрано",                    // 0
                    "Выбран |cffffff00%count%|r юнит",      // 1
                    "Выбрано |cffffff00%count%|r юнита",    // 4
                    "Выбрано |cffffff00%count%|r юнитов"    // 5
                )
            );

            ClearTextMessagesForPlayer(p);
            MessageForPlayer(p, s);
            
            DestroyGroup(g); g = null; 
        });
        
        // Создание юнита
        t = CreateTrigger();
        for(0 <= i < bj_MAX_PLAYER_SLOTS){
            TriggerRegisterPlayerChatEvent(t, Player(i), AddUnitCommand, false);
        }
        TriggerAddAction(t, function(){
            integer len = StringLength(AddUnitCommand) + 1;
            string s = SubString(GetEventPlayerChatString(), len, len+4);
            player p = GetTriggerPlayer();
            unit u;
            u = CreateUnit(p, S2RAW(s), GetRectCenterX(gg_rct_AddUnit), GetRectCenterY(gg_rct_AddUnit), GetRandomReal(0, 360));
            if (u == null){
                MessageForPlayer(p, StringReplace(AddUnitError, "%error%", s));
            } else {
                DestroyEffect(AddSpecialEffectTarget(AddUnitEfect, u, "origin"));
                MessageForPlayer(p, "Создан юнит: " + GetUnitNameColored(u));
            }
            
            u = null;
        });
    }

}
//! endzinc
» Item
//! zinc
library Item requires StringFunctions, Unit {
    constant string ManipulatedString = "%unit-name% %event-name% %item-name%. %item-count%.";
    constant string ManipulatedHelp = "Чтобы узнать равкод |cffffff00предмена|r, просто подберите его.";
    constant string AddItemCommand = "-item";
    constant string AddItemHelp = "Чтобы создать предмет наберите |cffffff00" + AddItemCommand + " |cff909090####|r.";
    constant string AddItemError = "|cffff0000Ошибка!|r Невозможно создать предмет |cffffff00%error%|r.";
    constant string AddItemEffect = "Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl";
    
    public {
        function GetItemNameColored(item i) -> string {
            return "|cffffff00" + GetItemName(i) + " |cff909090(" + RAW2S(GetItemTypeId(i)) + ")|r";
        }
    }
    
    function getItemCountString(unit u) -> string {
        integer i, count = 0;
        
        for (0 <= i < bj_MAX_INVENTORY){
            if (UnitItemInSlot(u, i) != null){
                count = count + 1;
            }
        }
        
        return Declenser(
            count,
            "%count%",
            "Рюкзак |c00fEBA0Eпуст|r",                  // 0
            "В рюкзаке |c00FFFC01%count%|r предмет",    // 1
            "В рюкзаке |c00FFFC01%count%|r предмета",   // 4
            "В рюкзаке |c00FFFC01%count%|r предметов"   // 5
        );
    }

    function manipulatedActions(unit u, item i, string s){
        string out;
        player p = GetOwningPlayer(u);
        
        TriggerSleepAction(0.01);
        
        ClearTextMessagesForPlayer(p);
        
        out = StringReplace(
            ManipulatedString,
            "%unit-name%",
            GetUnitNameColored(u)
        );
        
        out = StringReplace(
            out,
            "%event-name%",
            s
        );
        
        out = StringReplace(
            out,
            "%item-name%",
            GetItemNameColored(i)
        );
        
        out = StringReplace(
            out,
            "%item-count%",
            getItemCountString(u)
        );
        
        MessageForPlayer(GetOwningPlayer(u), out);
    }
    
    function onInit(){
        integer i;
        trigger t[];
        
        Message(AddItemHelp);
        Message(ManipulatedHelp);
        
        // Получение|Потеря|Использование предмета
        for (0 <= i <= 2){
            t[i] = CreateTrigger();
        }
        for(0 <= i < bj_MAX_PLAYER_SLOTS){
            TriggerRegisterPlayerUnitEvent(t[0], Player(i), EVENT_PLAYER_UNIT_PICKUP_ITEM, null);
            TriggerRegisterPlayerUnitEvent(t[1], Player(i), EVENT_PLAYER_UNIT_DROP_ITEM, null);
            TriggerRegisterPlayerUnitEvent(t[2], Player(i), EVENT_PLAYER_UNIT_USE_ITEM, null);
        }
        TriggerAddAction(t[0], function(){ 
            manipulatedActions(GetTriggerUnit(), GetManipulatedItem(), "получает");
        });
        TriggerAddAction(t[1], function(){ 
            manipulatedActions(GetTriggerUnit(), GetManipulatedItem(), "теряет");
        });
        TriggerAddAction(t[2], function(){ 
            manipulatedActions(GetTriggerUnit(), GetManipulatedItem(), "использует");
        });
        
        // Создание предмта
        t[3] = CreateTrigger();
        for(0 <= i < bj_MAX_PLAYER_SLOTS){
            TriggerRegisterPlayerChatEvent(t[3], Player(i), AddItemCommand, false);
        }
        TriggerAddAction(t[3], function(){
            integer len = StringLength(AddItemCommand) + 1;
            string s = SubString(GetEventPlayerChatString(), len, len+4);
            player p = GetTriggerPlayer();
            item i;
            real x = GetRectCenterX(gg_rct_AddUnit);
            real y = GetRectCenterY(gg_rct_AddUnit);
            i = CreateItem(S2RAW(s),x , y);
            if (i == null){
                Message(StringReplace(AddItemError, "%error%", s));
            } else {
                DestroyEffect(AddSpecialEffect(AddItemEffect, x, y));
                Message("Создан предмет: " + GetItemNameColored(i));
            }
            i = null;
        });
        
        
        for (0 <= i <= 3){
            t[i] = null;
        }
    }
}
//! endzinc

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

» Код библиотеки
/**********************************************************
*
* ВСЁ, ЧТО НИЖЕ, ПРАВИТЬ НА СВОЙ СТРАХ И РИСК!!!
*
**********************************************************/
//! zinc
library StringFunctions {
    constant real MessageDefaultTime = 60;
    // RAW
    constant string Alphabet = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrs​tuvwxyz{|}~";
    integer AlphabetValue[];
    string AlphabetIndex[];
    // Player Color
    string PlayerColor[];
    
    public {
        // Message
        function MessageTimed(string str, real time){ DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, time, str); }
        function Message(string str) { MessageTimed(str, MessageDefaultTime); }
        function MessageForPlayerTimed(player p, string str, real time){
            integer i;
            for(0 <= i < bj_MAX_PLAYER_SLOTS){
                if (GetLocalPlayer() == Player(i)){
                    Message(str);
                }
            }
        }
        function MessageForPlayer(player p, string str){ MessageForPlayerTimed(p, str, MessageDefaultTime); }
        
        // Clear Message
        function ClearTextMessagesForPlayer(player p){ if (GetLocalPlayer() == p){ ClearTextMessages(); } }
        
        // Player Name
        function GetPlayerColorString(player p) -> string { return PlayerColor[GetPlayerId(p)]; }
        function GetPlayerNameColored(player p) -> string { return GetPlayerColorString(p) + GetPlayerName(p) + "|r"; }
        
        // Trim
        function LTrim(string str, string found) -> string {
            integer i, len = StringLength(str), s = 0;
            for(0 <= i < len){
                if (SubString(str, i, i + 1) == found){ s = s + 1;}
                else { break; }
            }
            return SubString(str, s, len);
        }
        function RTrim(string str, string found) -> string {
            integer i, len = StringLength(str), e = len;
            for (len > i >= 0){
                if (SubString(str, i, i + 1) == found){ e = e - 1; }
                else { break; }
            }
            return SubString(str, 0, e);
        }
        function Trim(string str, string found) -> string {
            str = LTrim(str, found);
            str = RTrim(str, found);
            return str;
        }
        
        // B2S
        function B2S(boolean b) -> string {
            if (b) { return "true"; }
            return "false";
        }
        
        // RAW
        function RAW2S(integer ObjectId) -> string {
            integer i = 0, j = 4;
            string result = "";
            
            while(j > 0){
                i = R2I(ObjectId/AlphabetValue[j]);
                result = result + AlphabetIndex[i-31];
                ObjectId = ObjectId - i*AlphabetValue[j];
                j = j - 1;
            }
            return result;
        }
        function S2RAW(string ObjectId) -> integer {
            integer length = StringLength(ObjectId);
            integer result = 0;
            integer i = 0;
            integer j = 0;
            string objectPart;
            
            if (length != 4 ){ return 0; }
            while (true) {
                objectPart = SubString(ObjectId, j, j + 1);
                while(true){
                    i = i + 1;
                    if (AlphabetIndex[i] == objectPart) { break; }
                }
                result = result + (i+31)*AlphabetValue[4-j];
                j = j + 1;
                i = 0;
                if (j > 4) { break; }
            }
                
            return result;
        }
        
        // Replace
        function StringReplaceCounted(string str, string found, string replace, integer count) -> string {
            integer slen = StringLength(str);
            integer flen = StringLength(found);
            integer rlen = StringLength(replace);
            integer i, counted = 0;
            string s, c, out ="";
            
            // check
            if (slen == 0 || flen == 0 || flen > slen){ return str; }

            if (count >= 0){ // from left
                i = -1;
                while (i < slen - flen){
                    i = i + 1;
                    s = SubString(str, i, i+flen);
                    c = SubString(str, i, i+1);
                    if (s == found && (count == 0 || counted < count)){
                        i = i - 1 + flen;
                        counted = counted + 1;
                        out = out + replace;
                    } else {
                        out = out + c;
                    }
                }
                out = out + SubString(str, i+1, i+1+flen);
            } else { // from right
                i = slen;
                while (i >= flen){
                    i = i - 1;
                    s = SubString(str, i+1-flen, i+1);
                    c = SubString(str, i, i+1);
                    if (s == found && counted > count){
                        i = i + 1 - flen;
                        counted = counted - 1;
                        out = replace + out;
                    } else {
                        out = c + out;
                    }
                }
                out = SubString(str, 0, i) + out;
            } 
            return out;
        }
        function StringReplace(string str, string found, string replace) -> string {
            return StringReplaceCounted(str, found, replace, 0);
        }
        
        // Declension
        function Declension(integer number, string dec1, string dec4, string dec5) -> string {
            integer i;
            number = ModuloInteger(IAbsBJ(number), 100);
            if (number >= 11 && number <= 19) {
                return dec5;
            } else {
                i = ModuloInteger(number, 10);
                if (i == 1){
                    return dec1;
                } else if (i >= 2 && i<= 4){
                    return dec4;
                }
                return dec5;

            }
            return dec1;
        }
        function Declenser(integer number, string found, string dec0, string dec1, string dec4, string dec5) -> string {
            string out;
            
            if (number == 0){
                out = dec0;
            } else {
                out = Declension(number, dec1, dec4, dec5);
            }
            
            return StringReplace(out, found, I2S(number));
        }
        
    }
    
    function onInit(){
        integer i;
        
        // Player Color
        PlayerColor[0] = "|c00FF0303"; // red
        PlayerColor[1] = "|c000042FF"; // blue
        PlayerColor[2] = "|c001CE6B9"; // teal
        PlayerColor[3] = "|c00540081"; // purple
        PlayerColor[4] = "|c00FFFC01"; // yellow
        PlayerColor[5] = "|c00fEBA0E"; // orange
        PlayerColor[6] = "|c0020C000"; // green
        PlayerColor[7] = "|c00E55BB0"; // pink
        PlayerColor[8] = "|c00959697"; // gray
        PlayerColor[9] = "|c007EBFF1"; // lightblue
        PlayerColor[10] = "|c00106246"; // darkgreen
        PlayerColor[11] = "|c004E2A04"; // brown
        PlayerColor[12] = "|cff909090";
        PlayerColor[13] = "|cff909090";
        PlayerColor[14] = "|cff909090";        
        
        // RAW
        i = 0;
        while (true){
            i = i + 1;
            AlphabetIndex[i] = SubString(Alphabet, i-1, i);
            if (AlphabetIndex[i] == "") { break; }
        }
        AlphabetValue[1] = 1;
        AlphabetValue[2] = 256;
        AlphabetValue[3] = 256 * 256;
        AlphabetValue[4] = 256 * 256 * 256;

    }    
}
//! endzinc

Если понадобятся новые функции, пишите в комментариях


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

Bergi_Bear #1 - 8 месяцев назад 0
Вот теперь реально полезная наработка, ещё не запускал, но это именно оно о чем я говорил, круто!
А сделать CreateNewAbilityForUnit с изменением параметров способности сможешь?
NazarPunk #2 - 8 месяцев назад 0
Вот теперь реально полезная наработка
Да я просто понемногу реализую недостающий функционал, чтоб потом один раз импортировать и забыть)
А сделать CreateNewAbilityForUnit с изменением параметров способности сможешь?
Как оно работать то должно?
Bergi_Bear #3 - 8 месяцев назад (отредактировано ) 0
Как оно работать то должно?
Если бы я сам знал то сделал бы давно
но тема такая, нужно менять параметры у способности мемхаком, например манакост, дальность действия, базовое время перезарядки ну и описание естественно, а возможно и ещё много другое, ты то с мемхаком немножко знаком, это вроде как возможно, но тогда изменится у всех владельцев этой способности, поэтому есть вот такая тема:
В общем нужно создавать новые экземпляры способностей
NazarPunk #4 - 8 месяцев назад 0
В общем нужно создавать новые экземпляры способностей
Вещь полезная, но не люблю мемхак, сейчас вот думаю, как строку в игрока конвертировать, чтоб ловило 0, red, красный и в идеале начальные уникальные символы ника игрока)
pro100master #5 - 8 месяцев назад 0
NazarPunk, так создай конверт GetPlayerColor и сравнивая и узнаете цикл игрока
NazarPunk, либо в заранее занести в массив
NazarPunk #6 - 8 месяцев назад 0
pro100master, или проще, сделать комманду -players и вывести номера-ники игроков)
pro100master #7 - 8 месяцев назад 0
NazarPunk, это уже отдельная библиотека для игрока например в force только активных игроков и кто являет хостом и так далее и цветовые сообшения из него в функции вызываем и получаем счастья =)
library GamePlayers
endlibrary
а где функция для получение нужного параметра например "text,text,new" каждый запятой или указаный знак возврашали массив explode(",", "text,text,new", 2) вернет new нумерация с 0
NazarPunk #8 - 8 месяцев назад 0
а где функция для получение нужного параметра например "text,text,new" каждый запятой или указаный знак возврашали массив explode(",", "text,text,new", 2) вернет new нумерация с 0
Хорошая идея, жаль нельзя массивы возвращать. Добавить неложно, но как функции назвать то?
StringExplodeCount(string input, string delimiter) -> integer
StringExplodeParam(string input, string delimiter, integer number) -> string
pro100master #9 - 8 месяцев назад 0
NazarPunk, так пойдет
NazarPunk, и главное строка кешировать чтобы повторно цикл не проходить если надо получить параметры несколько раз =) если инпут ранее было то возврашаем старый массив это глобальный делай так
» Пример
//! zinc
library xeString {
    constant string xe_input = "";
    constant string xe_string[];

    public function StringExplodeSearch(string delimiter, string input, integer index) -> string {
        if (not(xe_input == input)) {
            // Проходим цикл так как старый инпут не найдено
        }
        return xe_string[index];
    }
    
    function onInit() {
    
    }
}
//! endzinc
NazarPunk #10 - 8 месяцев назад (отредактировано ) 0
и главное строка кешировать чтобы повторно цикл не проходить если надо получить параметры несколько раз =)
Экономия на спичках во время пожара. Проще несколько раз по строке пробежать, чем следить за кучей массивов и заставлять людей их обнулять за ненадобностью.
string s1 = StringExplodeSearch(...);
string s2 = StringExplodeSearch(...);
// И приехали
pro100master #11 - 8 месяцев назад 0
NazarPunk, он и обнуляет если инпут был другой задан
NazarPunk #12 - 8 месяцев назад 0
он и обнуляет если инпут был другой задан
string s1 = StringExplodeSearch(",", "1,2,3,4,5,6", 1);
string s2 = StringExplodeSearch(",", "7,8,9,10,11,12", 2);
string s3 = StringExplodeSearch(",", "1,2,3,4,5,6", 3);
И тут нам уже нужны двумерные массивы и хранение строки по хэшу. Проще пробежать по строке на каждый вызов и забить.
pro100master #13 - 8 месяцев назад 0
почему смотри
string s1 = StringExplodeSearch(",", "1,2,3,4,5,6", 0); Сработает 1 раз цикл
string s1 = StringExplodeSearch(",", "1,2,3,4,5,6", 3); из кеша
string s1 = StringExplodeSearch(",", "1,2,3,4,5,6", 5); из кеша
string s1 = StringExplodeSearch(",", "6,5,4,3,2,1", 0); новый инпут значит обнуляем кеш и проходим цикл
NazarPunk #14 - 8 месяцев назад (отредактировано ) 0
К тому же ещё нужно не забыть о косяках пользовательского ввода и заменить двойные пробелы
StringReplaceRepeated("old-----old---old-------old","-") -> string // old-old-old-old
Только с именами функций всётаки подумать прийдётся
pro100master:
почему смотри
string s1 = StringExplodeSearch(",", "1,2,3,4,5,6", 0); Сработает 1 раз цикл
string s2 = StringExplodeSearch(",", "1,2,3,4,5,6", 3); из кеша
string s3 = StringExplodeSearch(",", "6,5,4,3,2,1", 0); новый инпут значит обнуляем кеш и проходим цикл
string s4 = StringExplodeSearch(",", "1,2,3,4,5,6", 5); из кеша
Пользователь затупил, а виновата библиотека))
И ещё в документации это отразить нужно будет(
pro100master #15 - 8 месяцев назад 0
NazarPunk, сам решай как тебе удобно.. =)