openclonk/docs/sdk/script/ScriptPlayers.xml

121 lines
7.0 KiB
XML
Raw Normal View History

<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<!DOCTYPE doc SYSTEM "../../clonk.dtd">
<?xml-stylesheet type="text/xsl" href="../../clonk.xsl"?>
<doc>
<title>Scriptspieler</title>
<h>Scriptspieler</h>
<part>
<h id="Intro">Einleitung</h>
<text>Ab CR Build 265 ist es m<>glich, Spieler auch per Script beitreten zu lassen. Solche Spieler verhalten sich wie normale Spieler. Sie besitzen eine Crew, ein Konto, Heimatbasismaterial, ein Team, Baupl<70>ne, etc. Einziger Unterschied ist, dass sie von keinem Spieler gesteuert werden und auf keinem Rechner ein Sichtfenster f<>r diese Spieler ge<67>ffnet wird.</text>
<text>Scriptspieler sind n<>tzlich, um zum Beispiel KI-Gegner zu realisieren.</text>
<h id="Runtime">Beitritt zur Laufzeit</h>
<text>F<EFBFBD>rs Erstellen einer KI zur Laufzeit - zum Beispiel als Gegner im Deathmatch - dient <funclink>CreateScriptPlayer</funclink>. Daraufhin erfolgt (unter Umst<73>nden verz<72>gert, weil es sich um einen Spielerbeitritt handelt!) ein InitializePlayer-Aufruf f<>r diesen Scriptspieler. Da der Aufruf verz<72>gert ist, sollte die eigentliche KI-Initialisierung in diesem Aufruf passieren.</text>
<text>Dazu ein Beispiel:</text>
<code>/* Script einer aktivierten Spielregel namens "KI Erzeugen" */
#strict
public func Activate(int iPlr)
{
// Der Spieler iPlr hat die Spielregel ausgew<65>hlt. Erzeuge einen KI-Gegner!
<funclink>return</funclink>(<funclink>CreateScriptPlayer</funclink>("Computer", 0x7f7f7f));
}
protected func InitializePlayer(int iPlr)
{
// Ein Spieler ist beigetreten. Dieser Aufruf erfolgt an das Szenarienscript, sowie an alle Spielregeln,
// Spielziele und Umweltobjekte
// Ist es ein Scriptspieler?
<funclink>if</funclink> (<funclink>GetPlayerType</funclink>(iPlr) == C4PT_Script)
{
// Dann <20>bernimm die Steuerung f<>r alle Clonks!
var iCrew, pCrew;
<funclink>while</funclink> (pCrew = <funclink>GetCrew</funclink>(iPlr, iCrew++))
<funclink>AddEffect</funclink>("Int_EAI", pCrew, 1, 100, <funclink>this</funclink>());
}
}
protected func FxInt_EAITimer(object pCrew, int iEffNum, int iEffTime)
{
// N<>chsten Gegner angreifen
var pEnemy = <funclink>FindObject</funclink>(<funclink>Find_Hostile</funclink>(<funclink>GetOwner</funclink>(pCrew)), <funclink>Find_OCF</funclink>(<funclink>OCF_Alive</funclink>), <funclink>Sort_Distance</funclink>());
<funclink>if</funclink> (pEnemy) <funclink>SetCommand</funclink>(pCrew, "Attack", pEnemy);
<funclink>return</funclink> FX_OK;
}
</code>
<text>Dieses Beispielscript f<>r ein Regelobjekt erlaubt dem Spieler, zur Laufzeit KI-Gegner zu erstellen. Au<41>erdem sorgt es daf<61>r, dass alle Clonks dieses KI-Gegners angreifen. Achtung: Das Beispiel <20>bernimmt die Kontrolle nur f<>r alle Clonks, die der Spieler zu Spielbeginn nach Szenarienvorgaben erhalten hat. Wenn ein Szenarienscript zum Beispiel noch andere Clonks erstellen w<>rde, w<>rden diese nicht gesteuert.</text>
<text>F<EFBFBD>r Internetspiele kann man auch MaxScriptPlayers in der <emlink href="scenario/Teams.html">Teams.txt</emlink> auf einen Wert >0 setzen. Dann bekommt man in der Lobby die Option, Scriptspieler zu aktivieren. Diese Spieler treten auch wie gew<65>hnliche Spieler bei, und man sollte auch hier in InitializePlayer entsprechend das KI-Kontrollobjekt erstellen. Das obige Beispiel w<>rde also auch sofort mit in der Lobby aktivierten KI-Spielern funktionieren.</text>
<h id="Preset">Beitritt als Vorgabe</h>
<text>Wenn ein Szenario schon von Anfang an einen Scriptspieler beinhalten soll - zum Beispiel weil Objekte in der Objects.txt in dessen Besitz sein sollen, oder weil in Initialize Objekte f<>r diesen Spieler erzeugt werden, dann sollte man diesen wie in einem Savegame definieren. Also eine SavePlayerInfos.txt wie diese anlegen:</text>
<code>[PlayerInfoList]
LastPlayerID=1
[Client]
ID=0
Flags=Initial
[Player]
Name="Aliens"
Flags=Joined
ID=1
Type=Script
Team=2
Color=65535
GameNumber=1
GameJoinFrame=0
</code>
<text>Dies f<>hrt eine Spieler-Wiederherstellung durch, analog zur Wiederherstellung nach einem Savegame. Es wird also kein InitializePlayer f<>r diesen Spieler aufgerufen. Das Szenarienscript sollte in der Initialisierung die Crew f<>r diesen Spieler erstellen, oder es sollte eine entsprechende Crew in der Objects.txt vorhanden sein. Ansonsten wird der Scriptspieler sofort zum Spielbeginn eliminiert.</text>
<text>Scriptspieler werden im Gegensatz zu regul<75>ren Spielern ebenfalls gespeichert, wenn man in der Konsole "Speichern als Szenario" w<>hlt. Auf diese Weise kann man sich die richtige SavePlayerInfos.txt automatisch anlegen lassen. Dazu sollte einfach im Entwicklermodus manuell <funclink>CreateScriptPlayer</funclink> aufgerufen und dann Clonks f<>r diesen Scriptspieler verteilt werden. Speichert man dann als Szenario, wird der Scriptspieler mitgespeichert und steht beim Starten wieder zur Verf<72>gung.</text>
<h id="Specialized">Spezialisierte Spieler</h>
<text>Manchmal kann es sinnvoll sein, einen Scriptspieler erst zur Laufzeit zu erstellen aber trotzdem eine spezielle Initialisierung durchzuf<75>hren. Zum Beispiel sollte ein spezieller Alien-Gegner in einem Hazard-Deathmatch keine Hazardclonks erhalten.</text>
<text>Mit einem Parameter an <funclink>CreateScriptPlayer</funclink> lassen sich die szenarienspezifische Initialisierung, das hei<65>t das Erzeugen des Startmaterials, das Setzen der Startparameter nach Vorgaben und auch alle InitializePlayer-Aufrufe unterbinden. Stattdessen erfolgt nur ein InitializeScriptPlayer-Definitionsaufruf in der angegebenen Definition. Dazu ein Beispiel:</text>
<code>/* Script einer aktivierten Spielregel namens "Aliens erzeugen" */
#strict
public func Activate(int iPlr)
{
// Der Spieler iPlr hat die Spielregel ausgew<65>hlt. Erzeuge einen Alien-Gegner!
<funclink>return</funclink>(<funclink>CreateScriptPlayer</funclink>("Aliens", 0x00ff00, 0, CSPF_FixedAttributes | CSPF_NoScenarioInit, GetID()));
}
protected func InitializeScriptPlayer(int iPlr, int idTeam)
{
// Ein Alienspieler ist beigetreten
// Da keine Szenarieninitialisierung durchgef<65>hrt wurde, muss in diesem Callback eine Crew f<>r den Spieler erstellt werden
// Erstelle einen gr<67>nen Clonk - ein richtiges Szenario sollte nat<61>rlich echte Aliens mitbringen :)
var pAlien = CreateObject(CLNK, LandscapeWidth()/2, -1, iPlr);
MakeCrewMember(pAlien, iPlr);
SetClrModulation(0x7fff7f, pAlien);
// Und angreifen lassen
<funclink>AddEffect</funclink>("Int_EAI", pAlien, 1, 100, 0, GetID());
}
protected func FxInt_EAITimer(object pCrew, int iEffNum, int iEffTime)
{
// N<>chsten Gegner angreifen
var pEnemy = <funclink>FindObject</funclink>(<funclink>Find_Hostile</funclink>(<funclink>GetOwner</funclink>(pCrew)), <funclink>Find_OCF</funclink>(<funclink>OCF_Alive</funclink>), <funclink>Sort_Distance</funclink>());
<funclink>if</funclink> (pEnemy) <funclink>SetCommand</funclink>(pCrew, "Attack", pEnemy);
<funclink>return</funclink> FX_OK;
}
</code>
</part>
<author>Sven2</author><date>Dezember 2007</date>
</doc>