Appointment scheduler for turn-based games (inside your game)

Game development with Board Game Arena Studio
Post Reply
User avatar
dudi2
Posts: 215
Joined: 05 December 2015, 20:30

Appointment scheduler for turn-based games (inside your game)

Post by dudi2 »

For some games, that only work good as real-time games, it is very hard to find enough players for real-time games (because game is not played very often or game is in alpha phase with limited number of reviewers). For these games it is often much easier to start a game in turn-based mode.

But if people live in different time zones, without making any appointments it is difficult to be present at the table at the same time as all other players (resulting in games lasting months).

I tried to implement a basic version of an appointment tool keeping track of different time zones -- as an idea in a game implemented by me (currently alpha).

Question to admins and/or experienced developers: Is it allowed to remove the "checkAction" part in the code outlined below? That way everyone could update their availability at any time.


Outline of implementation (feel free to include and improve in your games, perhaps we have in future some solution inside the BGA-Framework based on this basic idea):


Somewhere in mygame_mygame.tpl (embedded in some divs and BEGIN/END player):

Code: Select all

<input type="datetime-local" id="mue_meetingtime_{PLAYER_ID}" name="mue_meetingtime_{PLAYER_ID}" {STATUS}>
in mygame.js:

Code: Select all

setup: function( gamedatas )
{
	//[...]
	// Show already set times
	for( var player_id in gamedatas.players )
	{
		var player = gamedatas.players[player_id];
		if (!this.bRealtime)
		{
			var input = document.getElementById('mygame_meetingtime_'+player_id);
			if (typeof input != 'undefined') {
				let currentLocalDate = new Date();
				let offset = currentLocalDate.getTimezoneOffset();
				let dt = new Date();
				dt.setTime(1*player['availability']-60000*offset);	// calculate local time
				if (currentLocalDate.getTime()-dt.getTime()<60000*offset) {	input.value = dt.toJSON().substr(0,16);	}
				else					   {	input.value = "";	}
			}
		}
	}

	//[...]
	// Appointment for turn-based play
	dojo.connect($("mygame_meetingtime_"+this.player_id), "onchange", this, "onChangeCalendarEntry");
	//[...]
}

onChangeCalendarEntry : function ()
{
	var action = 'setAppointment';
	let currentLocalDate = new Date();
	let selecteddatetime = document.getElementById("mygame_meetingtime_"+this.player_id).value;
	let selectedglobaldatetime = new Date(selecteddatetime);
	if (isNaN(selectedglobaldatetime.getTime())) {selectedglobaldatetime.setTime(0);}
	this.ajaxcall("/" + this.game_name + "/" + this.game_name + "/" + action + ".html", {
		id : this.player_id,
		datetime : selectedglobaldatetime.getTime(),	// save as global time
		fromstate : this.currentstatename,
		lock : true
	}, this, function( result ) { }, function( is_error ) { } );
},

In mygame.action.php:

Code: Select all

public function setAppointment() {
	self::setAjaxMode();
	$id = self::getArg("id", AT_posint, true);
	$datetime = self::getArg("datetime", AT_posint, true);
	$fromstate = self::getArg("fromstate", AT_alphanum, true);
	$this->game->saveAppointment($id,$datetime,$fromstate);
	self::ajaxResponse();
}		

In mygame.game.php (example with possilbe actions from my game):

Code: Select all

function saveAppointment( $player_id, $timestamp, $fromstate )
{
	// only allow to update if it is currently this players turn (is it allowed to remove this check?)
	if 	($fromstate=="auctionPlayerTurn")	{	self::checkAction("bidCard"); }
	else if ($fromstate=="selectTrumpVice") 	{	self::checkAction("selectViceTrump"); }
	else if ($fromstate=="selectTrumpChief") 	{	self::checkAction("selectChiefTrump"); }
	else if ($fromstate=="selectPartner") 		{	self::checkAction("selectPartner"); }
	else if ($fromstate=="trickPlayerTurn") 	{	self::checkAction("playCard"); }
	else 						{	self::checkAction("playCard"); }
	
	$sql = "UPDATE player SET player_availability=$timestamp WHERE player_id='$player_id' ";
	self::DbQuery($sql);
	
	$players = self::loadPlayersBasicInfos();
	$datetime = new DateTime;
	$datetime->setTimestamp($timestamp/1000);
	if ($timestamp==0)
	{
		self::notifyPlayer( $player_id, 'status', clienttranslate('You deleted your previously selected availability.'), array(
			'player_name' => $players[ $player_id ]['player_name'],
			'datetime' => $datetime->format('Y-m-d H:i')
		) );
	}
	else
	{
		self::notifyPlayer( $player_id, 'status', clienttranslate('You updated your availability to play this hand in real-time after the end of bidding phase: ${datetime}'), array(
			'player_name' => $players[ $player_id ]['player_name'],
			'datetime' => $datetime->format('Y-m-d H:i')
		) );
	}
}
In mygame.view.php:

Code: Select all

global $g_user;
foreach ( $player_to_dir_bid as $player_id => $dir ) {
	$status="disabled";
	if ($player_id == $g_user->get_id()) { $status=""; }
	$this->page->insert_block("player", array ("PLAYER_ID" => $player_id,
		"STATUS" => $status
		));
}
Requirement in dbmodel.sql:

Code: Select all

ALTER TABLE `player` ADD `player_availability` BIGINT UNSIGNED NOT NULL DEFAULT '0';


Comments and improvements are very welcome. I would love to have something like that inside BGA framework for any game (perhaps as tab like "Competition" "Tournament" "Options" "Credits" below the game)
User avatar
SwHawk
Posts: 133
Joined: 23 August 2015, 16:45

Re: Appointment scheduler for turn-based games (inside your game)

Post by SwHawk »

If you want non active players to be able to perform action outside of their turns, you can use:

Code: Select all

$this->gamestate->checkPossibleAction( $action )
which doesn't check if the active player is making the request. Please refer to the doc about states functions.

I haven't looked at the boilerplate code but should you be able to implement this, I might be interested to borrow your code.
Post Reply

Return to “Developers”