Writing a Game

From EQdkp Plus
Jump to navigation Jump to search


Game Builder

Try our Gamebuilder to create a basic Game with Classes, Races, Icons etc. But notice that the Gamebuilder only covers the basic functionality of games. You can enhance this created game.

API Level

With EQdkp Plus 2.0, we introduced an API Level for the Game Class. This ensures, that the old Games cannot produce fatal errors if they use removed methods of the Game Class. If we want to remove or rename Game Class Methods, we set them as deprecated (can be viewn if Debug-Mode is enabled). After two Increasements of the API Level, we will remove the method. That means that Games will not work anymore and loaded by the EQDkp Plus if their API-Level is Recent API level minus three.

That means that an module author has to update it's game regularly to make sure his game is working with the latest API.

Example

We want to remove a method in API Level 19. We set this method as deprecated and increase the API Level to 20. With API Level 22, this method will be removed. All games with an API Level lower 20 will not be loaded anymore and have to be adjusted to the new API Level.

API Levels

API-Level EQdkp Plus Version
20 2.0.0

Possibilies

With our game class, many things are possible. The Game that uses almost everything possible is World of Warcraft, therefore you should take a look at this Game. The following descriptions might not be complete, but should give you a hint how to do or what to look for.

Admin Settings

public function admin_settings() {
	$settingsdata_admin = array(
		'uc_server_loc'	=> array(
			'lang'		=> 'uc_server_loc',
			'type' 		=> 'dropdown',
			'options'	=> array('eu' => 'EU', 'us' => 'US', 'tw' => 'TW', 'kr' => 'KR', 'cn' => 'CN'),
		),
	);
	return $settingsdata_admin;
}

Profile fields

public function profilefields(){
	// Category 'character' is a fixed one! All others are created dynamically!
	$xml_fields = array(
		'guild'	=> array(
			'type'			=> 'text',
			'category'		=> 'character',
			'lang'			=> 'uc_guild',
			'size'			=> 40,
			'undeletable'	=> true,
			'sort'			=> 1
		),
		'servername'	=> array(
			'category'		=> 'character',
			'lang'			=> 'uc_servername',
			'type'			=> 'text',
			'size'			=> '21',
			'edecode'		=> true,
			'autocomplete'	=> $this->realmlist[$this->lang],
			'undeletable'	=> true,
			'sort'			=> 2
		),
	);
	return $xml_fields;
}

For Types take a look at this page.

Importers

Add this to the constructor of the Game Class

$this->importers = array(
	'char_import'		=> 'charimporter.php',						// filename of the character import
	'char_update'		=> 'charimporter.php',						// filename of the character update, member_id (POST) is passed
	'char_mupdate'		=> 'charimporter.php'.$this->SID.'&massupdate=true',		// filename of the "update all characters" aka mass update
	'guild_import'		=> 'guildimporter.php',						// filename of the guild import
	'import_reseturl'	=> 'charimporter.php'.$this->SID.'&resetcache=true',		// filename of the reset cache
	'guild_imp_rsn'		=> true,							// Guild import & Mass update requires server name
	'import_data_cache'	=> true,							// Is the data cached and requires a reset call?
);

Of course you have to write this files, but take a look at the Existing ones of WoW, because they need access to an API.

Calendar

Need: EQDKP 2.3.x Option to Hide Empty Roles in the Raids/Events

public $game_settings		= array(
	'calendar_hide_emptyroles'	=> true,    /*Calendar Hide Roles if zero*/
);

Char Infotooltip

Do get the additional Infos in the Calendar Events, which u set in the Char profile fields. In my Example, i have an additional field for PVP Players (Yes/No) and for a reduced Raid cooldown (18h/no).

	public function calendar_membertooltip($memberid){
			return array(
				$this->game->glang('uc_18h_Raid_cooldown').': '.$this->pdh->geth('member', 'profile_field', array($memberid, '18h_Raid_cooldown', true)),
				$this->game->glang('uc_pvp').': '.$this->pdh->geth('member', 'profile_field', array($memberid, 'pvp', true)),

	);

Chartooltip

public function chartooltip($intCharID){
	$template = $this->root_path.'games/'.$this->this_game.'/chartooltip/chartooltip.tpl';
	$content = file_get_contents($template);
	$charicon = $this->pdh->get('wow', 'charicon', array($intCharID));
	if ($charicon == '') {
		$charicon = $this->server_path.'images/global/avatar-default.svg';
	}
	$charhtml = '<b>'.$this->pdh->get('member', 'html_name', array($intCharID)).'</b><br />';
	$guild = $this->pdh->get('member', 'profile_field', array($intCharID, 'guild'));
	if (strlen($guild)) $charhtml .= '<br />&laquo;'.$guild.'&raquo;';
	
	$charhtml .= '<br />'.$this->pdh->get('member', 'html_racename', array($intCharID));
	$charhtml .= ' '.$this->pdh->get('member', 'html_classname', array($intCharID));
	$charhtml .= '<br />'.$this->user->lang('level').' '.$this->pdh->get('member', 'level', array($intCharID));
	
	
	$content = str_replace('{CHAR_ICON}', $charicon, $content);
	$content = str_replace('{CHAR_HTML}', $charhtml, $content);
	
	return $content;
}

Roster enhancement

Add subfolder "roster". Add file "roster_additions.php", where your code is defined. You have accesss in this file to the Data created by the normal roster page-object. Add "roster_view.html" with your Template Code in this subfolder.

Charview enhancement

Add subfolder "profile". Add profile_additions.php with your PHP Code, add profile_view.html with the Template Code.

Itemtooltips

Put your parser into subfolder "infotooltip". Example parser for Final Fantasy XIV.

<?php
 /*
 * Project:		EQdkp-Plus
 * License:		Creative Commons - Attribution-Noncommercial-Share Alike 3.0 Unported
 * Link:		http://creativecommons.org/licenses/by-nc-sa/3.0/
 * -----------------------------------------------------------------------
 * Began:		2010
 * Date:		$Date: 2014-03-20 14:44:33 +0100 (Do, 20 Mrz 2014) $
 * -----------------------------------------------------------------------
 * @author		$Author: wallenium $
 * @copyright	2006-2011 EQdkp-Plus Developer Team
 * @link		http://eqdkp-plus.com
 * @package		eqdkp-plus
 * @version		$Rev: 14134 $
 * 
 * $Id: zam.class.php 14134 2014-03-20 13:44:33Z wallenium $
 */

if(!class_exists('ffxiv_zam')) {
	class ffxiv_zam extends itt_parser {
		public static $shortcuts = array('pdl', 'puf' => 'urlfetcher', 'pfh' => array('file_handler', array('infotooltips')));

		public $supported_games = array('ffxiv');
		public $av_langs = array();

		public $settings = array();

		public $itemlist = array();
		public $recipelist = array();

		private $searched_langs = array();

		public function __construct($init=false, $config=false, $root_path=false, $cache=false, $puf=false, $pdl=false){
			parent::__construct($init, $config, $root_path, $cache, $puf, $pdl);
			$g_settings = array(
				'ffxiv' => array('icon_loc' => 'http:', 'icon_ext' => '', 'default_icon' => 'unknown'),
			);
			$this->settings = array(
				'itt_icon_loc' => array(	'name' => 'itt_icon_loc',
											'language' => 'pk_itt_icon_loc',
											'fieldtype' => 'text',
											'size' => false,
											'options' => false,
											'default' => ((isset($g_settings[$this->config['game']]['icon_loc'])) ? $g_settings[$this->config['game']]['icon_loc'] : ''),
				),
				'itt_icon_ext' => array(	'name' => 'itt_icon_ext',
											'language' => 'pk_itt_icon_ext',
											'fieldtype' => 'text',
											'size' => false,
											'options' => false,
											'default' => ((isset($g_settings[$this->config['game']]['icon_ext'])) ? $g_settings[$this->config['game']]['icon_ext'] : ''),
				),
				'itt_default_icon' => array('name' => 'itt_default_icon',
											'language' => 'pk_itt_default_icon',
											'fieldtype' => 'text',
											'size' => false,
											'options' => false,
											'default' => ((isset($g_settings[$this->config['game']]['default_icon'])) ? $g_settings[$this->config['game']]['default_icon'] : ''),
				),
			);
			$g_lang = array(
				'ffxiv' => array('en' => 'en_US', 'de' => 'de_DE', 'fr' => 'fr_FR'),
			);
			$this->av_langs = ((isset($g_lang[$this->config['game']])) ? $g_lang[$this->config['game']] : '');
		}

		public function __destruct(){
			unset($this->itemlist);
			unset($this->recipelist);
			unset($this->searched_langs);
			parent::__destruct();
		}
		
		private function getLangID($strLang){
			$arrLang = array(
				'en' => 1,
				'de' => 2,
				'fr' => 3,
			);
			return $arrLang[$strLang];
		}


		private function getItemIDfromUrl($itemname, $lang, $searchagain=0){
			$searchagain++;
			$encoded_name = urlencode($itemname);
			if (!$lang) $lang = "en";
			$link = "http://xivdb.com/modules/search/search.php?query=".$encoded_name."&page=1&pagearray=%7B%7D&language=".$this->getLangID($lang)."&filters=null&showview=0";			
			$data = $this->puf->fetch($link);
			$item_id = false;
			

			$this->searched_langs[] = $lang;
			if (preg_match_all('#href\=\"\?item\/(.*?)\/(.*?)\">(.*?)<\/a>#', $data, $matches))
			{				
				foreach ($matches[0] as $key => $match)
				{
					// Extract the item's ID from the match.
					$item_id = (int)$matches[1][$key];
					$found_name = strip_tags($matches[3][$key]);
					
					if(strcasecmp($itemname, $found_name) == 0) {
						return array($item_id, 'items');
					}
				}
			}
			
			//search in other languages
			if(!$item_id AND $searchagain < count($this->av_langs)) {
				$this->pdl->log('infotooltip', 'No Items found.');
				if(count($this->config['lang_prio']) >= $searchagain) {
					$this->pdl->log('infotooltip', 'Search again in other language.');
					$this->searched_langs[] = $lang;
					foreach($this->config['lang_prio'] as $slang) {
						if(!in_array($slang, $this->searched_langs)) {
							return $this->getItemIDfromUrl($itemname, $slang, $searchagain);
						}
					}
				}
			}
			
			return $item_id;
		}

		protected function searchItemID($itemname, $lang){
			return $this->getItemIDfromUrl($itemname, $lang);
		}

		protected function getItemData($item_id, $lang, $itemname='', $type='items'){
			$item = array('id' => $item_id);
			if(!$item_id) return null;
			
			$url = "http://xivdb.com/modules/fpop/fpop.php?callback=&lang=".$this->getLangID($lang)."&version=1.6&host=xivdb.com&type=item&id=".$item_id."&location=http%3A%2F%2Fxivdb.com%2F%3Ftooltip&convertQuotes=true&frameShadow=false&compact=false&statsOnly=false&replaceName=true&colorName=true&showIcon=true&_=1387608577170";
			$item['link'] = $url;
			$itemdata = $this->puf->fetch($item['link']);
			//$itemdata = substr(trim($itemdata), 1);
			//$itemdata = substr($itemdata, 0, -1);			
			$arrData = json_decode($itemdata);
			
			
			$strItemName = trim(strip_tags($arrData->name));

			if ($strItemName != ""){
				$item['icon'] = $arrData->icon;
				$item['color'] = $arrData->color;

				$template_html = trim(file_get_contents($this->root_path.'games/ffxiv/infotooltip/templates/ffxiv_popup.tpl'));
				$template_html = str_replace('{ITEM_HTML}', $arrData->html, $template_html);
				$item['html'] = $template_html;
				$item['lang'] = $lang;
				$item['name'] = $strItemName;
				
				
			} else {
				$item['baditem'] = true;
				
			}

			return $item;
		}
	}
}
?>

Raidexport

Put into subfolder "raidexport" a file with name GAME_NAME.class.php, e.g. "wow_autoinvite.class.php"

$rpexport_plugin['wow_autoinvite.class.php'] = array(
	'name'			=> 'WoW Auto Invite',
	'function'		=> 'wowautoinviteexport',
	'contact'		=> 'webmaster@wallenium.de',
	'version'		=> '2.0.0');

function wowautoinviteexport($raid_id){
  //Do Export Stuff
}

Add Ranks

Add to install() method of Game Class

$this->game->addRank($intID, $strName, $blnDefault=false, $strIcon='');
Example:
$this->game->addRank(0, "Guildmaster");

Add MultiDKP-Pools

Add to install() method of Game Class

$this->game->addMultiDKPPool($strName, $strDescription, $arrEventIDs, $arrItempoolIDs);
Example:
$this->game->addMultiDKPPool("Default", "Default MultiDKPPool", $arrEventIDs, array($intItempoolDefault));

Add Item-Pools

Add to install() method of Game Class

$this->game->addItempool($strName, $strDescription);
Example:
$this->game->addItempool("Classic", "Classic Itempool");

Add Events

Add to install() method of Game Class

$this->game->addEvent($strName, $intValue, $strIcon); //returns EventID
Example:
$this->game->addEvent($this->glang('mop_mogushan_10'), 0, "mv.png");

Add Raidgroup

Add to install() method of Game Class

$this->game->addRaidgroup($name, $color, $desc='', $standard=0, $sortid=0, $system=0);
Example:
$this->game->addRaidgroup("My New Raidgroup","#000000", "My Description");

Add Links

Add to install() method of Game Class

$this->game->addLink('$strName', '$strURL');
Example:
$this->game->addLink('Google', 'http://www.google.de/');

Cronjob

Options for the Cronjob, to be filled out by Admin; defined in your game class

public function cronjobOptions(){
	$arrOptions = array(
		'sync_ranks'	=> array(
				'lang'	=> 'Sync Ranks',
				'name'	=> 'sync_ranks',
				'type'	=> 'radio',
		),
	);
	return $arrOptions;
}

The real cronjob, defined in your game class

public function cronjob($arrParams = array()){
	$blnSyncRanks = ((int)$arrParams['sync_ranks'] == 1) ? true : false;

	//Do a lot of other stuff
}

Languages

The language files are placed at the game-subfolder languages. The files are named after their language, e.g. german.php or englisch.php.

<?php
if ( !defined('EQDKP_INC') ){
	header('HTTP/1.0 404 Not Found');exit;
}
$german_array = array(
	'factions' => array(
		'alliance'	=> 'Allianz',
		'horde'		=> 'Horde'
	),
	'races' => array(
		'Unbekannt',
		'Gnom',
		'Mensch',
		'Zwerg',
		'Nachtelf',
		'Troll',
		'Untoter',
		'Ork',
		'Taure',
		'Draenei',
		'Blutelf',
		'Worg',
		'Goblin',
		'Pandaren'
	),
);

//Since 2.3, you can add main language to overwrite EQdkp Plus Language Vars
$lang_array = array(
     'menu_members' => 'Tanks'	// for core-languages find in /install-dir/language/..
     'pdh_lang_member_name_decorated'	=> 'Tankname',  // for module-languages find in /install-dir/core/data_handler/includes/modules/.. ($module_lang)
     'pdh_preset_lang_mname' => 'Tank-Name', // for preset-languages find in /install-dir/core/data_handler/includes/modules/.. ($preset_lang)
);
?>

Updates (Since 2.3)

This section is for EQdkp Plus 2.3.

Games can now include own updates. Create the subfolder includes/updates/ in your game folder. In this folder, you can create update files using the following scheme:

update_<GAMENAME>_<VERSION_OF_NEW_VERSION>.class.php
//Example:
update_albiononline_220.class.php

The update class is the same as it is for extensions. Here is an example, which brings an update class that will get executed.

<?php
/*	Project:	EQdkp-Plus
 *	Package:	GuildRequest Plugin
 *	Link:		http://eqdkp-plus.eu
 *
 *	Copyright (C) 2006-2016 EQdkp-Plus Developer Team
 *
 *	This program is free software: you can redistribute it and/or modify
 *	it under the terms of the GNU Affero General Public License as published
 *	by the Free Software Foundation, either version 3 of the License, or
 *	(at your option) any later version.
 *
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU Affero General Public License for more details.
 *
 *	You should have received a copy of the GNU Affero General Public License
 *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

if (!defined('EQDKP_INC')){
	header('HTTP/1.0 404 Not Found');exit;
}

include_once(registry::get_const('root_path').'maintenance/includes/sql_update_task.class.php');

if (!class_exists('update_albiononline_220')){
	class update_albiononline_220 extends sql_update_task {

		public $author		= 'GodMod';
		public $version		= '2.2.0';    // new version
		public $name		= 'Albiononline 2.2.0 Update';
		public $type		= 'plugin_update';
		public $game_path	= 'albiononline'; // important!

		/**
		* Constructor
		*/
		public function __construct(){
			parent::__construct();

			// init language
			$this->langs = array(
				'english' => array(
					'update_albiononline_220'	=> 'Albiononline 2.2.0 Update Package',
					'update_function' 			=> 'Update Settings',
				),
				'german' => array(
					'update_albiononline_220'	=> 'Albiononline 2.2.0 Update Paket',
					'update_function'			=> 'Aktualisiere Einstellungen',
				),
			);

		}
		
		public function update_function(){
			echo "Hello World";
			return true;
		}
	}
}
?>