Writing a Game
Contents
- 1 Game Builder
- 2 API Level
- 3 Possibilies
- 4 Languages
- 5 Updates (Since 2.3)
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 />«'.$guild.'»';
$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;
}
}
}
?>