This is a documentation for Board Game Arena: play board games online !

БГА Студио Цоокбоок

Извор: Board Game Arena
Пређи на навигацију Пређи на претрагу

Тхис паге ис цоллецтион оф десигн анд имплементатион реципес фор БГА Студио фрамеwорк. Фор тоолинг анд усаге реципес сее Тоолс анд типс оф БГА Студио. Иф yоу хаве yоур оwн реципес феел фрее то едит тхис паге.

Висуал Еффецтс, Лаyоут анд Аниматион

Цреате пиецес дyнамицаллy (усинг темплате)

Ингредиентс: ггг_ггг.тпл, ггг.јс

Ноте: тхис метход ис рецоммендед бy БГА гуилдлинес

Децларед јс темплате wитх вариаблес ин .тпл филе, лике тхис

<script type="text/javascript">
    // Javascript HTML templates
    var jstpl_ipiece = '<div class="${type} ${type}_${color} inlineblock" aria-label="${name}" title="${name}"></div>';
</script>

Усе ит лике тхис ин .јс филе

 div = this.format_block('jstpl_ipiece', {
                               type : 'meeple',
                               color : 'ff0000',
                               name : 'Bob',
                           });
 

Тхен yоу до wхатевер yоу неед то до wитх тхат див, тхис оне специфицаллy десигн то го то лог ентриес, бецаусе ит хас ембеддед титле (отхерwисе итс а пицтуре онлy) анд но ид.

Ноте: yоу цоулд хаве плаце тхис вариабле ин јс итселф, бут кеепинг ит ин .тпл аллоwс yоу то хаве yоур јс цоде бе фрее оф ХТМЛ. Нормаллy ит невер хаппенс бут ит ис гоод то стриве фор ит. Ноте: yоу цан алсо усе стринг цонцатенатион, итс лесс реадабле. Yоу цан алсо усе дојо дом објецт цреатион апи'с бут итс бруталлy вербосе анд итс море унреадабле.


Цреате пиецес дyнамицаллy (усинг стринг цонцатенатион)

Ингредиентс: ггг.јс

Ноте: Нот рецоммендед

  div = "<div class='meeple "+color+"'></div>";

Цреате алл пиецес статицаллy

Ингредиентс: ггг_ггг.тпл, ггг.цсс, ггг.виеw.пхп (оптионал)

  • Цреате АЛЛ гаме пиецес ин хтмл темплате (.тпл)
  • АЛЛ пиецес схоулд хаве униqуе ид, анд ит схоулд бе меанингфул, и.е. меепле_ред_1д
  • До нот усе инлине стyлинг
  • Ид оф плаyер'с специфиц пиецес схоулд усе соме сорт оф 'цолор' идентифицатион, синце плаyер ид цаннот бе усед ин статиц лаyоут, yоу цан усе енглисх цолор наме, хеx 6 цхар валуе, ор цолор "нумбер" (1,2,3...)
  • Пиецес схоулд хаве сепаратед цласс фор итс цолор, тyпе, етц, со ит цан бе еасилy стyлед ин гроупс. Ин еxампле белоw yоу ноw цан стyле алл мееплес, алл ред мееплес ор алл ред токенс, ор алл "фирст" мееплес

ин .тпл филе:

 
  <div id="home_red" class="home red">
     <div id="meeple_red_1" class="meeple red n1"></div>
     <div id="meeple_red_2" class="meeple red n2"></div>
  </div>

ин .цсс филе:

.meeple {
	width: 32px;
	height: 39px;
	background-image: url(img/78_64_stand_meeples.png);
	background-size: 352px;
}

.meeple.red {
	background-position: 30% 0%;
}
  • Тхере схоулд бе страигхт форwард маппинг бетwеен сервер ид анд јс ид (ор 1:1)
  • Yоу плаце објецтс ин дифферент зонес оф тхе лаyоут, анд сетуп цсс то таке царе оф лаyоут
.home .meeple{
   display: inline-block;
}
  • Иф yоу неед то хаве а темпорарy објецт тхат лоок лике оригинал yоу цан усе дојо.цлоне (анд цханге ид то соме темп ид)
  • Иф тхере ис лотс оф репетитион ор зоне грид yоу цан усе темплате генератор, бут ињецт стyле децларатион ин цсс инстеад оф инлине стyле фор флеxибилитy

Ноте:

  • Иф yоу усе тхис модел yоу цаннот усе премаде јс цомпонентс суцх ас Стоцк анд Зоне
  • Yоу хаве то усе алтернативе метходс оф аниматион (слигхтлy алтеред) синце дефаулт метход wилл леаве објецт wитх инлине стyле аттрибутес wхицх yоу дон'т неед

Усе тхематиц фонтс

Ингредиентс: ггг.цсс

Сометиме гаме елементс усе специфиц фонтс оф теxт, иф yоу wант то матцх ит уп yоу цан лоад соме специфиц фонт (фром соме фрее фонт соурце).

Драгонлине фонт.пнг

.цсс

/* latin-ext */
@font-face {
  font-family: 'Qwigley';
  font-style: normal;
  font-weight: 400;
  src: local('Qwigley'), local('Qwigley-Regular'), url(https://fonts.gstatic.com/s/qwigley/v6/2Dy1Unur1HJoklbsg4iPJ_Y6323mHUZFJMgTvxaG2iE.woff2) format('woff2');
  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Qwigley';
  font-style: normal;
  font-weight: normal;
  src: local('Qwigley'), local('Qwigley-Regular'), url(https://fonts.gstatic.com/s/qwigley/v6/gThgNuQB0o5ITpgpLi4Zpw.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
@font-face {
  font-family: 'Qwigley';
  font-style: normal;
  font-weight: normal;
  src: local('Qwigley'), local('Qwigley-Regular'), url(http://ff.static.1001fonts.net/q/w/qwigley.regular.ttf) format('ttf');
}

.zone_title {
	display: inline-block;
	position: absolute;
	font: italic 32px/32px "Qwigley", cursive;	   
	height: 32px;
	width: auto;
}


Усе плаyер цолор ин темплате

Ингредиентс: ггг_ггг.тпл, ггг.виеw.пхп

.виеw.пхп:

    function build_page($viewArgs) {
        // Get players & players number
        $players = $this->game->loadPlayersBasicInfos();
        $players_nbr = count($players);
        /**
         * ********* Place your code below: ***********
         */
        
        // Set PCOLOR to the current player color hex
        global $g_user;
        $cplayer = $g_user->get_id();
        if (array_key_exists($cplayer, $players)) { // may be not set if spectator
            $player_color = $players [$cplayer] ['player_color'];
        } else {
            $player_color = 'ffffff'; // spectator
        }
        $this->tpl ['PCOLOR'] = $player_color;


Ињецт имагес анд стyлед хтмл ин тхе лог

Ингредиентс: ггг.јс, ггг.гаме.пхп

Со yоу wант нице пицтурес ин тхе гаме лог, wхат до yоу до? Фирст идеа тхат цоме то минд ис то сенд хтмл фром пхп ин нотифицатионс. Тхис ис бад идеа фор манy реасонс

  • Итс бад арцхитецтуре, уи елементс леак инто сервер ноw yоу хаве то манаге уи ин манy плацес
  • Иф yоу децидед то цханге сометхинг ин уи ин футуре версион, олд гамес реплy анд туториалс маy нот wорк, синце тхеy усе сторед нотифицатионс
  • Wхен yоу реад лог превиеw фор олд гамес итс унреадабле (тхис ис лог бефоре yоу ентер тхе гаме реплy, усефул фор троублесхоотинг ор гаме аналyсис)
  • Итс море дата то трансфер анд сторе ин дб
  • Итс нигхтмаре фор транслаторс

Со wхат елсе цан yоу до? I усе тхис реципе wхицх I ис цлиент сиде лог ињецтион. I интерцепт лог аргументс анд реплаце тхем бy хтмл он мy цлиент сиде.

Цлиентлогињецтион.пнг

ггг.јс

 

        /** Override this function to inject html for log items  */

        /* @Override */
        format_string_recursive : function(log, args) {
            try {
                if (log && args && !args.processed) {
                    args.processed = true;
                    args.You = this.divYou(); // will replace ${You} with colored version

                    // list of other known variables
                    var keys = ['place_name','token_name'];
                    
                  
                    for ( var i in keys) {
                        var key = keys[i];
                        if (typeof args[key] == 'string') {
                           args[key] = this.getTokenDiv(key, args);                            
                        }
                    }
                }
            } catch (e) {
                console.error(log,args,"Exception thrown", e.stack);
            }
            return this.inherited(arguments);
        },

        /* Implementation of proper colored You with background in case of white or light colors  */

        divYou : function() {
            var color = this.gamedatas.players[this.player_id].color;
            var color_bg = "";
            if (this.gamedatas.players[this.player_id] && this.gamedatas.players[this.player_id].color_back) {
                color_bg = "background-color:#" + this.gamedatas.players[this.player_id].color_back + ";";
            }
            var you = "<span style=\"font-weight:bold;color:#" + color + ";" + color_bg + "\">" + __("lang_mainsite", "You") + "</span>";
            return you;
        },



        getTokenDiv : function(key, args) {
            // ... implement whatever html you want here, example from sharedcode.js
            var token_id = args[key];
            var item_type = getPart(token_id,0);
            var logid = "log" + (this.globalid++) + "_" + token_id;
            switch (item_type) {
                case 'wcube':
                    var tokenDiv = this.format_block('jstpl_resource_log', {
                        "id" : logid,
                        "type" : "wcube",
                        "color" : getPart(token_id,1),
                    });
                    return tokenDiv;
                    break;
                case 'meeple':
                    if ($(token_id)) {
                        var clone = dojo.clone($(token_id));
    
                        dojo.attr(clone, "id", logid);
                        this.stripPosition(clone);
                        dojo.addClass(clone, "logitem");
                        return clone.outerHTML;
                    }
                    break;
     
                default:
                    break;
            }

            return "'" + this.clienttranslate_string(this.getTokenName(token_id)) + "'";
       },
       getTokenName : function(key) {
           return this.gamedatas.token_types[key].name; // get name for the key, from static table for example
       },

Ноте ин тхис цасе сервер симплy ињецтс токен_ид ас наме, анд цлиент субститутес ит фор тхе реал транслатед наме ор тхе пицтуре

ггг.гаме.пхп:

          $this->notifyPlayer($player_id,'playerLog',clienttranslate('${You} moved cube'),['You'=>'You']);

ггг.гаме.пхп:

          $this->notifyAllPlayers('playerLog',clienttranslate('Game moves ${token_name}'),['token_name'=>$token_id]);

Ноw иф yоу дон'т лике раw лог цонтаининг ид инстеад оф наме бут wант наме, анд wант субститутион, yоу цан усе анотхер параметер ас ид. Тхе проблем wитх тхат, ит wилл wорк ат фирст, бут иф yоу релоад гаме усинг Ф5 yоу wилл лоосе yоур аддитионал параметерс, wхy? Бецаусе wхен гаме релоадс ит доес нот ацтуаллy сенд саме нотифицатионс, ит сендс специал "хитсторицал_лог" нотифицатион wхере алл параметерс нот листед ин тхе "лог" аре ремовед. Тхере ис а хацк (феатуре) то цирцумвент тхат, цаллед рецурсиве параметерс. I.е. yоу цан сенд стуфф лике тхис:

            $this->notifyAllPlayers('playerLog',clienttranslate('Game moves ${token_name_rec}'),
                   ['token_name_rec'=>['log'=>'${token_name}',
                                       'args'=> ['token_name'=>clienttranslate('Boo'), 'token_id'=>$token_id, 'i18n'=>['token_name'] ]
                                      ]
                   ]);

анд ин формат_лог_рецурсиве

            var key = 'token_name';
            if (typeof args[key] == 'string' && typeof args['token_id'] == 'string') {
                args[key] = this.getTokenDiv('token_id', args);                            
            }

Гаме Модел анд Датабасе десигн

Датабасе фор Тхе еуро гаме

Летс саy wе хаве а гаме wитх wоркерс, дице, токенс, боард, ресоурцес, монеy анд вп. Wоркерс анд дице цан бе плацед ин вариоус зонес он тхе боард, анд yоу цан гет ресоурцес, монеy, токенс анд вп ин yоур хоме зоне. Алсо токенс цан бе флиппед ор нот флиппед.

Мадеира боард.пнг


Ноw летс трy то мап ит, wе хаве

  • (меепле,зоне)
  • (дие, зоне, сидеуп)
  • (ресоурце цубе/монеy токен/вп токен,плаyер хоме зоне)
  • (токен, плаyер хоме зоне, флип стате)

Wе цан нотице тхат ресоурце анд монеy аре унцоунтабле, анд дон'т неед то бе трацк индивидуаллy со wе цан реплаце оур маппинг то

  • (ресоурце тyпе/монеy,плаyер хоме зоне, цоунт)

Анд вп сторед алреадy фор ус ин плаyер табле, со wе цан ремове ит фром тхат лист.

Ноw wхен wе гет то енцоде ит wе цан сее тхат еверyтхинг цан бе енцодед ас (објецт,зоне,стате) форм, wхере објецт анд зоне ис стринг анд стате ис интегер. Тхе ресоурце маппинг ис слигхтлy дифферент семантицаллy со yоу цан го wитх тwо табле, ор цоунтинг усинг саме табле wитх стате беен усед ас цоунт фор ресоурцес.

Со тхе пиеце маппинг фор нон-грид басед гамес цан бе ин мост цасе репресентед бy (стринг: токен_кеy, стринг: лоцатион, инт: стате), еxампле оф суцх датабасе сцхема цан бе фоунд хере: дбмодел.сqл анд цласс имплементинг аццесс то ит хере табле.гаме.пхп.

Вариант 1: Минималистиц

CREATE TABLE IF NOT EXISTS `token` (
 `token_key` varchar(32) NOT NULL,
 `token_location` varchar(32) NOT NULL,
 `token_state` int(10),
 PRIMARY KEY (`token_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


токен
токен_кеy токен_лоцатион токен_стате
меепле_ред_1 хоме_ред 0
дице_блацк_2 боард_гуард 1
дице_греен_1 боард_ацтион_маyор 3
бреад хоме_ред 5


Вариант 2.1: Аддитионал ресоурце табле, усинг саме лоцатион ас токен табле

CREATE TABLE IF NOT EXISTS `resource` (
 `resource_type` varchar(32) NOT NULL,
 `resource_location` varchar(32) NOT NULL,
 `resource_count` int(10) signed NOT NULL,
 PRIMARY KEY (`resource_type`,`resource_location`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ресоурце
ресоурце_тyпе ресоурце_лоцатион ресоурце_цоунт
бреад хоме_ред 5

Вариант 2.2: Аддитионал ресоурце табле, ресоурце цоунт фор еацх плаyер ид

CREATE TABLE IF NOT EXISTS `resource` (
 `player_id` int(10) unsigned NOT NULL,
 `resource_key` varchar(32) NOT NULL,
 `resource_count` int(10) signed NOT NULL,
 PRIMARY KEY (`player_id`,`resource_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE resource ADD CONSTRAINT fk_player_id FOREIGN KEY (player_id) REFERENCES player(player_id);
ресоурце
плаyер_ид ресоурце_кеy ресоурце_цоунт
123456 бреад 5

Вариант 3: Море нормалисед

Тхис версион ис симилар то "цард" табле фром хеартс туториал, yоу цан алсо усе еxацт цардс датабасе сцхема анд Децк имплементатион фор мост пурпосес (евен yоу нот деалинг wитх цардс).

CREATE TABLE IF NOT EXISTS `token` (
 `token_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `token_type` varchar(16) NOT NULL,
 `token_arg` int(11) NOT NULL,
 `token_location` varchar(32) NOT NULL,
 `token_state` int(10),
 PRIMARY KEY (`token_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
токен
токен_ид токен_тyпе токен_арг токен_лоцатион токен_стате
22 меепле 123456 хоме_123456 0
23 дице 2 боард_гуард 1
26 дице 1 боард_ацтион_маyор 3
49 бреад 0 хоме_123456 5

Адвантагес оф тхис wоулд бе ис а бит море страигхтфорwард то до соме qуериес ин дб, дисадвантаге итс хард то реад (ас yоу цан цомпаре wитх превиоус еxампле, yоу цаннот јуст лоок ат саy, ах I кноw wхат ит меанс). Анотхер qуестионабле адвантаге ис ит аллоwс yоу то до ид рандомисатион, со ит хард то до црафтед qуериес то цхеат, тхе доwн сиде оф тхат yоу цаннот ундерстанд ит еитхер, анд хандцрафт дб статес фор дебуггинг ор тестинг.

Датабасе фор Тхе цард гаме

Летс саy yоу хаве а стандард цард гаме, плаyер хаве хидден цардс ин ханд, yоу цан драw цард фром драw децк, плаy цард он таблеау анд дисцард то дисцард пиле. Wе хаве то десигн датабасе фор суцх гаме.

Ин реал wорд то "саве" тхе гаме wе таке а пицтуре а плаy ареа, саве цардс фром ит, тхен пут аwаy драw децк, дисцард анд ханд оф еацх плаyер сепарателy анд марк ит, алсо wе wилл рецорд цуррент сцоринг (иф анy) анд wхо'с турн wас ит.

  • Фрамеwорк хандлес стате мацхине транситион, со yоу дон'т хаве то wоррy абоут датабасе десигн фор тхат (и.е. wхо'с турн ит ис, wхат пхасе оф тхе гаме wе аре ат, yоу стилл хаве то десигн ит бут парт оф стате мацхине степ)
  • Алсо фрамеwорк суппортс басиц плаyер информатион, цолор, ордер ароунд тхе табле, басиц сцоринг, етц, со yоу дон'т хаве то wоррy абоут ит еитхер
  • Тхе онлy тхинг yоу неед ин оур датабасе ис стате оф тхе "боард", wхицх ис "wхере еацх пиецес ис, анд ин wхат стате", ор (поситион,ротатион) паир.

Летс сее wхат wе хаве фор тхат:

  • Тхе цард стате ис верy симпле, итс усуаллy "фаце уп/фаце доwн", "таппед/унтаппед", "ригхт сиде уп/уп сиде доwн"
  • Ас поситион го wе невер неед реал цоординатес x,y,з. Wе неед то кноw wхат "зоне" цард wас, анд депендинг он тхе зоне ит маy сометимес неед ан еxтра "з" ор "x" ас цард ордер. Тхе зоне поситион усуаллy статиц ор иррелевант.
  • Со оур модел ис: wе хаве цардс, wхицх хаве соме аттрибутес, ат анy гивен поинт ин тиме тхеy белонг то а "зоне", анд цан алсо хаве ордер анд стате
  • Ноw фор маппинг wе схоулд цонсидер wхат информатион цхангес анд wхат информатион ис статиц, латер ис алwаyс цандидате фор материал филе
  • Фор дyнамиц информатион wе схоулд трy то редуце амоунт оф фиелдс wе неед
    • wе неед ат леаст а фиелд фор цард, со итс оне
    • wе неед то кноw wхат зоне цардс белонг то, итс 2
    • анд wе хаве поссиблy феw отхер фиелдс, иф yоу лоок цлоселy ат yоу гаме yоу маy финд оут тхат мост оф тхе зоне онлy неед оне аттрибуте ат а тиме, и.е. драw пиле алwаyс хаве цардс фаце доwн, ханд алwаyс фаце уп, алсо фор ханд анд дисцард ордер доес нот маттер ат алл (бут фор драw ит доес маттер). Со ин мајоритy оф цасес wе цан гет аwаy wитх оне сингле еxтра интегер фиелд репресентинг стате ор ордер
  • Ин реал датабасе ботх цард анд зоне wилл бе интегерс ас примарy кеyс реферринг то аддитионал таблес, бут ин оур цасе итс тотал оверкилл, со тхеy цан бе стрингс ас еасилy

Вариант 1: Минималистиц

CREATE TABLE IF NOT EXISTS `card` (
  `card_key` varchar(32) unsigned NOT NULL,
  `card_location` varchar(32) NOT NULL,
  `card_state` int(11) NOT NULL,
  PRIMARY KEY (`card_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;


Вариант 2: Море нормалисед

Тхис версион суппортед бy Децк пхп цласс, со унлесс yоу wант то реwрите дб аццесс лаyер го wитх тхис оне

CREATE TABLE IF NOT EXISTS `card` (
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `card_type` varchar(16) NOT NULL,
  `card_type_arg` int(11) NOT NULL,
  `card_location` varchar(16) NOT NULL,
  `card_location_arg` int(11) NOT NULL,
  PRIMARY KEY (`card_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Ноте: иф yоу усинг тхис сцхема, соме зонес/лоцатионс хаве специал семантиц. Тхе 'ханд' лоцатион ис ацтуаллy мултипле лоцатионс - оне пер плаyер, бут плаyер ид ис енцодед ас цард_лоцатион_арг. Иф 'ханд' ин yоур гаме ис ордеред, висибле ор цан хаве соме отхер цард статес, yоу цаннот усе ханд лоцатион (реплацемент ис ханд_<плаyер_ид> ор ханд_<цолор_ид>)

Ассортед Стуфф

Мулти Степ Интерацтионс: Селецт Wоркер/Плаце Wоркер - Усинг Цлиент Статес

Ингредиентс: ггг.јс

I дон'т тхинк итс доцументед феатуре бут тхере ис а wаy то до цлиент-онлy статес, wхицх ис абсолутелy wондерфул фор феw реасонс

  • Wхен плаyер итератион ис тwо степ процесс, суцх ас селецт wоркер, плаце wоркер, ор плаце wоркер, пицк оне оф тwо ресоурцес оф yоур цхоице
  • Wхен мулти-степ процесс цан ресулт оф импоссибле ситуатион анд хас то бе ундоне (бy рулес)
  • Wхен мулти-степ процесс ис триггеред фром мултипле статес (суцх ас yоу цан до саме тхинг ас ацтиватед цард ацтион, пасс ацтион ор маин ацтион)

Со летс до Селецт Wоркер/Плаце Wоркер

Дефине yоур сервер стате ас усуал, и.е. плаyерМаинТурн -> "Yоу муст пицк уп а wоркер". Ноw дефине а цлиент стате, wе онлy неед "наме" анд "десцриптионмyтурн", летс саy "цлиент_плаyерПицксЛоцатион". Алwаyс префиx намес оф цлиент стате wитх "цлиент_" то авоид цонфусион. Ноw wе хаве то до тхе фоллоwинг:

  • Хаве а хандлер фор онУпдатеАцтионБуттонс фор плаyерМаинТурн то ацтивате алл поссибле wоркерс хе цан пицк
  • Wхен плаyер цлицкс wоркерс, ремембер тхе wоркер ин оне оф тхе мемберс оф тхе маин цласс, I усуаллy усе оне цаллед тхис.цлиентСтатеАргс.
  • Транситион то неw цлиент стате
 onWorker: function(e) {
     var id = event.currentTarget.id;
     dojo.stopEvent(event);
     ... // do validity checks
     this.clientStateArgs.worker_id = id;
     this.setClientState("client_playerPicksLocation", {
                               descriptionmyturn : "${you} must select location",
                           });
  }
  • Хаве а хандлер фор онУпдатеАцтионБуттонс фор цлиент_плаyерПицксЛоцатион то ацтивате алл поссибле лоцатионс тхис wоркер цан го АНД адд Цанцел буттон (сее белоw)
  • Хаве а лоцатион хандлер wхицх wилл евентуаллy сенд а сервер реqуест, усинг сторед тхис.цлиентСтатеАргс.wоркер_ид ас wоркер ид
  • Тхе цанцел буттон схоулд цалл а метход то ресторе сервер стате, алсо иф yоу доинг ит фор море тхан оне стате yоу цан адд тхис универсаллy усинг тхис.он_цлиент_стате цхецк


       if (this.isCurrentPlayerActive()) {
         if (this.on_client_state && !$('button_cancel')) {
              this.addActionButton('button_cancel', _('Cancel'), dojo.hitch(this, function() {
                                            this.restoreServerGameState();
              }));
         }
       } 

Ноте: усуаллy I цалл мy оwн фунцтион цалл тхис.цанцелЛоцалСтатеЕффецтс() wхицх wилл до море стуфф фирст тхен цалл рестореСерверГамеСтате(), саме фунцтион ис усуаллy неедс то бе цаллед wхен сервер реqуест хас фаилед (и.е. инвалид мове)

Ноте: Иф yоу неед море тхан 2 степс, yоу маy хаве то до цлиент сиде аниматион то рефлецт тхе неw стате, wхицх гетс трицкиер бецаусе yоу хаве то ундо тхат алсо он цанцеллатион.

Цоде ис аваилабле хере схаредцоде.јс (итс усинг плаyерТурнПлаyЦубес анд цлиент_селецтЦубеЛоцатион).


Мулти Степ Интерацтионс: Ацтион Стацк - Усинг Цлиент Статес

Ингредиентс: ггг.јс, ггг.гаме.пхп, материал.инц.пхп

  • Wе хаве еуро гаме wхере гаме ацтионс цонсист оф сериес оф мини-ацтионс, wхицх цан бе триггеред бy мултипле соурцес
  • Еxампле: Руссиан РаилРоадс хаве мултипле соурце оф ацтионс, суцх ас wоркер слотс, триггеред адвантагес, триггеред фацторy реwардс, етц. Еацх оф тхе цонсист оф сериес оф смалл ацтион, суцх ас "адванце блацк раил + адванце маркер", онце yоу старт еxецутинг ит, море мини-ацтионс аре триггеред анд аддед то тхе стацк (ин цасе оф РРР итс нот а стацк бут а рандом аццесс лист бут wхатевер)
  • Имплементинг суцх гаме wитх сервер статес ис ратхер диффицулт бецаусе
    • ит реqуире лотс оф статес
    • реqуире стацк он тхе стате мацхине то суппорт ретурн то тхе стате wе оригинатед субстате фром
    • сериес цан ресулт ин инвалид гаме стате (и.е. нот аллоwед бy рулес), wхицх ит хард то ролл бацк овер мултипле статес
    • wитхоут ундо ит wоулд бе ратхер фрустратинг фор тхе плаyер, анд ундо ис хард то имплемент

Со тхис ис хоw то имплементед ит усинг ацтион стацк анд цлиент статес

Енцоде алл мини-ацтионс ас идентифиер ор а леттер, I усе леттерс персоналлy

Фор еацх ацтион, триггер, етц, дефине а "рулес" оф тхат гаме елемент усинг мини-ацтион енцодинг анд сторе ин материал.инц.пхп со ботх сервер анд цлиент хаве аццесс то ит, но неед то сторе ит ин датабасе, рулес аре нот гоинг то цханге дуринг тхе гаме.

материал.инц.пхп:

$this->token_types = array(
 ...
'slot_action_14' => array(
 'name' => clienttranslate("Industry Advancement"),
 'rules'=>"i",
),
'slot_action_15' => array(
 'name' => clienttranslate("2 Industry Advancements"),
 'rules'=>"ii",
),
'slot_action_16' => array(
 'name' => clienttranslate("Industry and Black Track Advancement"),
 'rules'=>"ib",
),
);


Ин гаме.пхп yоу сенд тхис то цлиент ггг.гаме.пхп:

   protected function getAllDatas() {
       ...
       // this is material fields
       $result ['token_types'] = $this->token_types;
       ...
  }

Ин .јс wхен цлиент селецтс оригинал ацтион, yоу реад тхис фиелд анд пусх ацтионс инто стацк, сометхинг лике

        this.pushOperations(this.gamedatas.token_types[action_id].rules);
        this.processAction();

Анд процессАцтион() wилл аллоw усер то деал wитх поссибле ацтионс. Иф тхис ис трулy а стацк yоу цоулд хаве доне сометхинг лике

   processAction: function() {
        var op = this.popOperation();
        switch (op) {
             case 'i': 
               this.setClientState("client_playerTurnSelectAdvantageToken", {
                              descriptionmyturn : "${you} must select industry marker to move",
                          });
               break;
            ...
        }
   }

Ин Руссиан Раилроадс итс унордеред лист, со ит хас то оффер усер алл поссибле цхоицес дривен бy цуррент унпроцессед оператионс, тхен детермине wхат оператион wас тхат фром тхе лист басед он wхат тхеy цлицкед, и.е.

       onMoveable : function(event) {
                           ...
                           else if (id.startsWith('ind')) {
                               if (!this.commitOperation('i', id, place_id)) return;
                           }
                           this.gamedatas_local.tokens[id] = place_id; // alter local model
                           this.placeToken(id, place_id); // client side animation
                           if (this.checkAchievementMoveable(new_state, old_state, id)) { // that will check if something is triggered, so we can push more stuff on the stack
                              this.processAction();
                           }
        }

Дуринг цлиент статес дата ис цоллецтед анд пусхед инто цлиент арраy оф перформед оператионс, wе алсо до цлиент сиде аниматион анд алтер модел, синце wе дон'т сенд интермедиате степс то сервер.

Ин еxампле абове wе цхецк иф wе цлиент он индустрy маркер, wе wилл "цоммит" "и" оператион wитх селецтед ид оф тхе маркер анд плаце_ид. Тхе цоммит ис јуст пусхинг тхис дата инто ан арраy.

Алл тхис оператионс латер аре сенд то сервер, усуаллy wхен усер цлицкс Доне. Тхе дата wилл бе енцодед фор сервер то реад инто а стринг, и.е. и__инд2__индслот15, меанс мове индустрy маркер нумбер 2 инто слот 15 оф индустрy трацк. Анд мултипле оператионс цан бе сепаратед бy а спаце фор еxампле.

Ат анyтиме дуринг цлиент статес усер цан цлицк Цанцел wхицх wилл ресторе ласт сервер стате анд ундо алл цлиент аниматион бацк то ласт сторед стате.

Тхе онлy дисадвантаге оф тхис метход ис yоу хаве то имплемент а лот оф фунцтионалитy тwо тимес - он сервер анд цлиент.