Ich habe gerade ein Forum installiert – hier können wir uns ganz ungezwungen austauschen – wenn jemand daran Interesse hat
Das Forum findet ihr hier: http://www.logd.info/logd-forum/
Ich habe gerade ein Forum installiert – hier können wir uns ganz ungezwungen austauschen – wenn jemand daran Interesse hat
Das Forum findet ihr hier: http://www.logd.info/logd-forum/
Hier ein Service für alle LoGD-Admins die einen Server auf logd.info betreiben:
Ab sofort ist der Zugriff auf die Datenbank möglich, ohne ein eigenes PhpMyAdmin zu installieren. Genaue Infos gibt es hier im Wiki.
Der Grund für die heutige kurzzeitige Nicht-Erreichbarkeit von logd.info waren kleinere Serverarbeiten. Diese sind nun abgeschlossen und der normale Betrieb kann weitergehen.
Nachtrag: Beim Versuch diesen Artikel zu veröffentlichen habe ich gemerkt das etwas nicht passt. Ich musste alle Twitter-Plugins aus WordPress deaktiviern und löschen bevor eine Veröffentlichung des Textes möglich war. Ich vermute einmal das das aber nichts mit dem Umzug zu tun hat – wahrscheinlich ist es eher ein Bug in WordPress.
Heute habe ich die Einstellungen auf logd.info dahingehend geändert, das ab sofort jeder registrierte Benutzer eigene Beiträge schreiben kann. Somit kann jeder z.B. seinen Lieblings-LoGD-Server vorstellen und/oder rezensieren. Diese Beiträge werden dann auf der Serverliste verlinkt.
Um die kleine Tutorial-Reihe rund um die Zaubertränke abzuschließen, hier noch ein kleiner Artikel wie man dem Spieler ein kleines “Zaubersäckchen” anzeigen kann. In diesem werden die gekauften Tränke aufbewahrt und können von hier aus auch aktiviert werden. Um das “Zaubersäckchen” in der Vitalinfo anzuzeigen, muß in der common.php nach folgendem Code gesucht werden:
if (!is_array($session[bufflist])) $session[bufflist]=array();
$charstat.=appoencode(templatereplace("statbuff",array("title"=>"Aktionen","value"=>$buffs)),true);
Dann fügt man folgenden Code danach ein:
#### ZAUBERSÄCKCHEN ####
if (true)
{
$charstat .= addcharstat("Zaubersäckchen");
$sql = 'SELECT id, name, count(*) AS anzahl FROM items ';
$sql.='WHERE class = "Potion" and owner='.$session['user']['acctid'];
$sql.=' GROUP BY name';
$result = db_query($sql);
$anz_rows = db_num_rows($result);
if($anz_rows==0)
{
$charstat.=addcharstat("Leer","");
}
else
{
for($i=0;$i<$anz_rows;$i++)
{
$row = db_fetch_assoc($result);
$sName = trim(substr($_SERVER['PHP_SELF'],1));
if($sName == 'forest.php' || $sName == 'gebirge.php' ||
$sName == 'ocean.php' || $sName == 'news.php' ||
$sName == 'about.php' || $sName == 'prefs.php' ||
$sName == 'en_usePotion.php')
{
// hier die items nur anzeigen, nicht verlinken
$charstat.=addcharstat($row['name'], 'x' . $row['anzahl']);
// addnav('', 'en_usePotion.php?id='.$row['id'].'&return='.substr($_SERVER['PHP_SELF'],1));
}
else
{
$charstat.=addcharstat('<a href="en_usePotion.php?id='.$row['id'].'&return='.substr($_SERVER['PHP_SELF'],1).'">'.$row['name'].'</a>', 'x' . $row['anzahl']);
addnav('', 'en_usePotion.php?id='.$row['id'].'&return='.substr($_SERVER['PHP_SELF'],1));
}
}
}
}
################
Das “Zaubersäckchen” erscheint nun in der Vitalinfo direkt unter den Aktionen. Man kann das natürlich ändern in dem man den Code an einer anderen Stelle einfügt.
Kurz zur Erklärung: Es werden also alle, dem Spieler gehörenden, Tränke angezeigt. Mit einem Klick auf den ensprechenden Trank wird dieser aktiviert (en_usePotion.php aufgerufen). Bei einigen Skripten ist das jedoch nicht möglich (forest.php, news.php, prefs.php, …) da hier eine Unterbrechung des Skriptes nicht erwünscht ist. Wenn man also noch andere Skripte (Orte) hat, an denen keine Tränke benutzt werden dürfen, dann muss einfach die entsprechende Abfrage erweitert werden.
So, nun viel Spaß beim Tränke brauen!
Wie im Artikel “Zaubertränke in LoGD verwenden” schon angekündigt, möchte ich in diesem Artikel beschreiben wie die selbst erstellten Zaubertränke nun auch von den Spielern benutzt werden können.
Dazu habe ich ein Skript geschrieben, welches mit der ID des Zaubertrankes aufgerufen werden muß. In diesem werden die entsprechenden Buffs des Zaubertrankes ausgewertet und der Spieler bekommt die Auswirkungen sofort zu spüren. Wenn dem Skript auch ein “Rückkehrsript” übergeben wird, landet der Spieler danach an diesem Ort, anderenfalls findet er/sie sich auf dem Dorfplatz wieder (village.php).
Das Skript ist recht einfach gehalten, deswegen möchte ich hier nur kurz auf die Funktion doAction() eingehen, die für jede Zeile der im Trank enthaltenen Buffs aufgerufen wird:
function doAction($line)
{
global $session;
// hier werden die spalten in ein array gepackt
$col = explode(' ', $line);
$value = (int)trim($col[2]);
$target = trim($col[1]);
switch($target)
{
case 'hitpoints':
$text='Lebenspunkte';
break;
case 'turns':
$text='Runden';
break;
case 'deathpower':
$text='Gefallen';
break;
case 'reputation':
$text='Ansehen';
break;
case 'charm':
$text='Charme';
break;
case 'experience':
$text='Erfahrungspunkte';
break;
case 'maxhitpoints':
$text='permanente Lebenspunkte';
break;
default:
// kein gültiges schlüsselwort, also raus hier
return;
}
$action = trim($col[0]);
switch($action)
{
case 'ADD':
// hinzufügen
output('Du erhälst '.$col[2].' ' . $text . '`n');
$session['user'][$target] += $col[2];
break;
case 'SUB':
// abziehen
output('Du verlierst '.$col[2].' ' . $text . '`n');
$session['user'][$target] -= $col[2];
break;
case 'SET':
// setzen
output('Du hast nun '.$col[2].' ' . $text . '`n');
$session['user'][$target] = $col[2];
break;
default:
// hier passiert nix
break;
}
Was passiert hier? Am besten zeige ich das an einem kleinen Beispiel. Wir rufen die Funktion einmal mit einer Buffzeile auf:
doAction("SUB hitpoints 5")
Nun wird in der Funktion als erstes die übergeben Zeile in ein Array aufgesplittet. Im Array befindet sich also am Index 0 die Aktion die ausgeführt werden soll (SUB, ADD oder SET). Am Index 1 finden wir das Ziel, als WAS gesetzt werden soll (hier die Lebenspunkte). Am Index 2 schließlich ist der Wert gespeichert um wieviel geändert werden soll.
mit switch($target) { … } wird je nach Ziel ein entsprechender Text definiert, der dem Spieler anzeigt was genau passiert ist. Das folgende switch($action) { … } entscheidet anhand des Schlüsselwortes was zu tun ist, tut das auch und gibt eine entsprechende Meldung aus.
Und wo werden die Tränke nun angezeigt damit der Spieler sie auswählen kann? Das verrate ich im dritten Teil.
Wie schon im ersten Teil beschrieben, möchte ich in diesem Tutorial einen kleinen Quest für das von mir programmierte LoGD-Questsystem entwickeln. Es handelt sich hierbei um folgende Aufgabe:
Der Spieler soll eine gewisse Anzahl eines bestimmten Gegners im Wald (z.B. Waldkobolde) erledigen und dafür eine Belohnung erhalten. Der Quest muss bei einem NPC (Non-Player-Character) “abgeholt” werden und dort auch wieder beendet werden.Für dieses Tutorial sind Kenntnisse der objektorientierten Programmierung mit PHP von Vorteil, ich hoffe jedoch das ich es so hinbekomme das jeder diesen Quest “nachbauen” kann.
Jeder Quest wird durch eine eigene Datei repräsentiert. Diese muss sich im Verzeichnis “quests” auf dem Server befinden. Der Name der Datei sollte dem Questnamen entsprechen, damit man sie später auch schnell wiederfinden kann. In unserem Fall erstellen wir eine Datei “Waldkobolde.class”. Am Ende dieses Artikels befindet sich der Link zur kompletten Datei. Wer keine eigenen Quests erstellen möchte, kann sich die Datei herunterladen und wie am Ende des Artikels beschrieben einbinden. Für alle, die eigene Quests programmieren wollen, wird dringend empfohlen dieses Tutorial durchzuarbeiten um die Funktionsweise des Systems kennen zu lernen.
Da wir beim OOP (objektorientiertes Programmieren) mit Klassen und Objekten arbeiten erstellen wir also eine Klasse “Waldkobolde”:
<?php
/*
* Quest: Die Waldkobolde
* Entwickelt von Haderlump für logd.info
*/
/**
* Klasse Waldkobolde
*
* @author Haderlump
*/
final class Waldkobolde extends Quest {
public function Waldkobolde($dbg=false)
{
$DEBUG = $dbg;
$this->load('Waldkobolde');
$this->setRepeats(5);
}
}
Was passiert hier? Wir erstellen eine Klasse “Waldkobolde” aus der Vorlage “Quests”. Im Initialisierer der Klasse, dem wir den Parameter $dbg (=Debugger einschalten TRUE/FALSE) mitgeben können, wird mit der Methode $this->load(‘Waldkobolde’) der Quest geladen. Die Logik dazu steckt bereits in der Klasse “Quests” und muss uns hier nicht weiter interessieren. Mit der Methode $this->setRepeats(5) legen wir fest, wie oft der Quest wiederholt werden darf, in diesem Falle fünf Mal.
Nun brauchen wir in unserer Klasse noch einige Methoden, die in der Klasse “Quests” als abstrakt definiert wurden. Das bedeutet, die Funktionen müssen von uns ausprogrammiert werden damit das Ganze funktioniert. Es handelt sich um folgende Methoden:
protected function resetVariables()
{
}
public function getDescription()
{
}
protected function getReward()
{
}
public abstract function getRewardText()
{
}
public abstract function getStatus($format='')
{
}
protected abstract function getStatustableContent()
{
}
public abstract function isComplete()
{
}
Diese Methoden müssen wir nun, nach und nach, mit Leben füllen. Beginnen wir mit der Methode resetVariables():
protected function resetVariables()
{
global $session;
$session['user']['slorion']['q_Waldkobolde'] = 0;
}
Hier setzen wir alle Variablen, die für diesen Quest benötigt werden, wieder auf den Anfangszustand zurück. In unserem Fall wird die Anzahl der bereits erledigten Waldkobolde in der Variablen $session['user']['slorion']['q_Waldkobolde'] gespeichert. In dem wir diese auf 0 (Null) setzen, beginnen wir also den Quest wieder von vorn.
Als nächstes die Methode getDescription():
public function getDescription()
{
return "Finde und töte 10 Waldkobolde. Kehre danach zu
Haderlump zurück.";
}
Diese Methode gibt uns eine kurze Beschreibung des Quests zurück. Hier können alle üblichen Formatierungen und Farbcodes verwendet werden. Diese Methode werden wir später im entsprechenden Skript aufrufen, um dem Spieler anzuzeigen was ihn bei diesem Quest überhaupt erwartet.
Die Methode getReward() belohnt den Spieler nachdem der Quest erfolgreich beendet wurde. Mit dem Aufruf dieser Methode werden dem Spieler alle definierten Belohnungen gutgeschrieben.
protected function getReward()
{
global $session;
$session['user']['gold']+=100;
$session['user']['experience']+=10;
}
In unserem Fall bekommt der Spieler 100 Goldstücke und 10 Erfahrungspunkte. Hier sind der Fantasie keine Grenzen gesetzt – z.B. können auch Gegenstände in die items-Tabelle eingefügt werden, oder der Spieler könnte ebenso auch sterben
Weiter gehts mit der Methode getRewardText():
public function getRewardText()
{
return 'Du erhälst 100 Goldstücke und 10 Erfahrungspunkte.';
}
Hier wird der Text für die Belohnung ausgegeben, damit der Spieler auch weiss was er bekommen hat. Auch hier sind wieder alle Formatierungen erlaubt.
Die Methode getStatus($format=”) liefert uns, und später dem Spieler, eine Übersicht über den aktuellen Status seines Quests.
public final function getStatus($format='table')
{
global $session;
switch($format)
{
case 'table':
// rückgabewert als html-tabelle
$ret = $this->getStatustableHeader();
$ret.= $this->getStatustableContent();
$ret.= $this->getStatustableFooter();
break;
default:
// rückgabewert als array[][name][ist][soll]
$ret = array();
$ret[] = array('Waldkobold', $session['user']['slorion']['q_Waldkobolde'], 10);
break;
}
return $ret;
}
Abhängig vom übergebenen Parameter können wir hier dem Benutzer verschiedene Möglichkeiten der Darstellung bieten. Im Standardfalle wird ein Array mit den entsprechenden Werten geliefert. Mehr dazu aber im dritten Teil des Tutorials. Die Methode getStatustableContent() gehört unmittelbar zur Methode getStatus() und liefert den HTML-Code für die (Standard-)Status-Tabelle.
protected function getStatustableContent()
{
global $session;
if(!isset($session['user']['slorion']['q_Waldkobolde']))
{
$session['user']['slorion']['q_Waldkobolde']=0;
}
return '<tr><td>Waldkobolde</td><td>'.$session['user']['slorion']['q_Waldkobolde'].'</td><td>10</td></tr>';
}
Zu guter Letzt folgt noch die Methode isComplete():
public final function isComplete()
{
global $session;
if($session['user']['slorion']['q_Waldkobolde']==10)
{
return true;
}
else
{
return false;
}
}
Hier werden die Bedingungen für den erfolgreichen Abschluss des Quests ausgewertet, und dementsprechend ein TRUE bzw. FALSE zurückgegeben. Hier haben wir also das Ziel erreicht, wenn in der Variablen $session['user']['slorion']['q_Waldkobolde'] der Wert 10 steht.
Damit hätten wir alle von der Hauptklasse vorgegebenen Methoden definiert. Und siehe da: Unser erster Quest ist fertig! Die komplette Datei “Waldkobolde.class.php” muss nun noch in den Ordner “quests” auf den Server geladen werden. Um die Datei verfügbar zu machen fehlt noch der Eintrag
require_once('quests/Waldkobolde.class.php');
unter dem zuvor eingefügten Eintrag für die Quests.class.php.
Wie das Ganze nun auf dem LoGD-Server zum Einsatz gebracht werden kann, werde ich im dritten Teil des Tutorials erklären.
So, nach langem Warten und auf Grund der mehrfachen Nachfrage einer einzelnen Person (
) raffe ich mich nun auf und werde versuchen mein Quest-System für Legend of the Green Dragon der Allgemeinheit zur Verfügung zu stellen.
Die Programmierung wurde objektorientiert ausgeführt, das Einbinden in einen bestehenden Server sollte jedoch nicht zu aufwändig sein. Es gibt jedoch einige Sachen zu beachten, ohne die die Skripte nicht funktionieren werden.
Grundlegend sollte die Modifikation der accounts-Tabelle, wie hier beschrieben, am Server durchgeführt sein. Wenn nicht, sind Änderungen an den Skripten notwendig!
Um den aktuellen Questfortschritt speichern zu können, benötigt man eine neue Tabelle “quests”. Diese kann hier heruntergeladen werden: quests_sql. Nach dem Entpacken muss die Datei z.B. mit phpmyadmin in die Datenbank importiert werden.
Weiters brauchen wir auf dem Server ein Verzeichnis “quests”, direkt im Hauptverzeichnis. In diesem Ordner werden die Quests dann gespeichert. Als erstes muss in diesem Ordner die Datei Quest.class.php hochgeladen werden. Dieses ist die Vorlage für alle anderen Quests. Um sie verfügbar zu machen, brauchen wir noch einen Eintrag in der Datei “common.php”:
/*
* Haderlumps Quest-System
*/
require_once('quests/Quest.class.php');
Dieser Eintrag kann z.B. ganz am Ende der Datei eingetragen werden.
Nun sind alle Voraussetzungen erfüllt. Das System solle nach wie vor fehlerfrei funktionieren.
Es wird Zeit einen ersten Quest mit dem System zu erstellen. Ein Tutorial für einen “Waldkobolde”-Test findet ihr im nächsten Beitrag.
Was mich an der accounts-Tabelle bei LoGD immer gestört hat, war das fast jedes Special oder Skript ein oder mehr zusätzliche Felder benötigt um die speziellen Daten abzuspeichern.
Auf meinem Server habe ich es daher so gelöst, das ich nur ein Feld in die accounts-Tabelle eingefügt habe (z.B. “slorion”) und in diesem dann alle anderen Informationen gespeichert habe. Da es sich hierbei um ein Array handelt, können so ganz leicht immer wieder neue Daten gespeichert werden.
Der Zugriff auf die Daten erfolgt dann immer über das Feld
$session['user']['slorion']
Habe ich nun z.B. ein Special programmiert, welches nur 1 mal pro DK aufrufbar sein soll, so kann ich das folgendermassen speichern wenn das Special aufgerufen wurde:
$session['user']['slorion']['specialname'] = 1
und am Anfang des Specials frage ich diesen Wert wieder ab:
if($session['user']['slorion']['specialname']<1) {
... Hier kommt das Special ...
} else {
... Hier wird nichts ausgeführt ...
}
Leider hat diese Methode auch einige Nachteile. So ist es z.B. nicht möglich in einer Abfrage nach einem in diesem Feld gespeicherten Wert zu sortieren. Auch muß das gesamte Feld einen DK “überleben” und die Unterfelder evtl. nach einem DK manuell zurückgesetzt werden. Meiner Meinung nach überwiegen bei dieser Methode jedoch die Vorteile. Wenn man Sortierung etc. braucht, kann man die accounts-Tabelle ja immer noch erweitern.
Um nun diese Funktion auf dem eigenen LoGD-Server einzusetzen braucht es ein wenig Vorbereitung:
if ($session[loggedin]){
$sql = "SELECT * FROM accounts WHERE acctid = '".$session[user][acctid]."'";
$result = db_query($sql);
if (db_num_rows($result)==1){
$session[user]=db_fetch_assoc($result);
$session[output]=$session[user][output];
$session[user][dragonpoints]=unserialize($session[user][dragonpoints]);
$session[user][prefs]=unserialize($session[user][prefs]);
### SET THE SLORION VAR ###
if($session['user']['slorion'] == "") {
$session['user']['slorion'] = array();
} else {
$session['user']['slorion'] = unserialize($session['user']['slorion']);
}
### SET THE SLORION VAR ###
Jetzt haben wir die Variable jederzeit im Zugriff. Gespeichert wird sie automatisch in der common.php mit folgendem Code (bin mir nicht sicher ober der ursprünglich vorhanden war, oder ob ich das gebaut habe):
$sql="UPDATE accounts SET ";
reset($session[user]);
while(list($key,$val)=each($session[user])){
if (is_array($val)){
$sql.="$key='".addslashes(serialize($val))."', ";
}else{
if($key == "name") {
$sql.="$key='".trim(addslashes($val))."', ";
} else {
$sql.="$key='".addslashes($val)."', ";
}
}
}
$sql = substr($sql,0,strlen($sql)-2);
$sql.=" WHERE acctid = ".$session[user][acctid];
db_query($sql);
Nun muss noch die Datei “dragon.php” modifiziert werden. Einfach mal nach “$nochange” suchen, und am Ende
$nochange['slorion'] = true;
einfügen. Jetzt wird der Inhalt der Variablen nach einem Drachenkill nicht mehr gelöscht. Möchte man jedoch einzelne Werte bei einem DK zurücksetzen, kann man diese nach der eben eingefügten Zeile auf die entsprechenden Werte initialisieren. Bei Slorion sieht das z.B. so aus:
// VARIABLEN DIE PRO DRACHENKILL GELÖSCHT WERDEN $session['user']['slorion']['bakery']['milch'] = 0; $session['user']['slorion']['bakery']['torte1'] = 0; $session['user']['slorion']['bakery']['torte2'] = 0; $session['user']['slorion']['bakery']['torte3'] = 0; $session['user']['slorion']['potion'] = 0;
Nun gibt es auch Werte die mit jedem neuen Tag auf einen bestimmten Wert gesetzt werden müssen. Auch hierfür gibt es eine Lösung. Diese müssen in der Datei “newday.php” gesetzt werden. Wieder ein Beispiel:
####### VARIABLEN DIE TÄGLICH GELÖSCHT WERDEN ###### $session['user']['slorion']['gildgefused'] = 0; $session['user']['slorion']['richtplatz'] = 0; $session['user']['slorion']['druidenhain'] = 0;
Jetzt ist das System einsatzfähig und es können nach Belieben Variablen gesetzt werden, ohne jedesmal neue Spalten in der accounts-Tabelle hintufügen zu müssen.
Die meisten der hier vorgestellten Skripte werden die Variable $session['user']['slorion'] benutzen. Es ist also sinnvoll die Änderungen an Hand dieses Tutorials einzubauen. Natürlich können auch die Skripte geändert werden. Dabei muss dann “einfach” die Variable $session['user']['slorion'] durch die entprechende andere Variable ersetzt werden.