Hilfreiche Funktionen in MMM
-
- Süßwasserpirat
- Beiträge: 258
- Registriert: 22.09.2002, 21:28
- Kontaktdaten:
Hilfreiche Funktionen in MMM
1. Es wird immer nur die Interaction „Any click on ...“ verwendet... keine anderen!
2. Es gibt im Global Script definierte Funktionen, die in Interaction-Scripts verwendet werden können und die Scripts teilweise wesentlich verkürzen:
a) FaceDirection
Anstelle von FaceLocation kann FaceDirection verwendet werden, wenn der Character in eine bestimmte Richtung und nicht auf einen bestimmten Punkt schauen soll:
FaceDirection (CharId, DIR_UP);
FaceDirection (CharId, DIR_LEFT);
FaceDirection (CharId, DIR_DOWN);
FaceDirection (CharId, DIR_RIGHT);
Hierdurch wird das Script auch leichter lesbar.
b) EnterRoom
Anstelle von NewRoom kann der Playercharacter mit EnterRoom in einen neuen Raum an eine bestimmte Stelle geschickt werden:
EnterRoom (int room, int x, int y, int dir);
Für „dir“ werden die Konstanten von FaceDirection verwendet.
c) GiveInv und GiveInvEx
GiveInv (int invitem, int charid)
PlayerCharacter gibt invitem an charid.
GiveInvEx (int invitem, int charidfrom, int charidto)
charidfrom gibt invitem an charidto.
d) MovePlayer und abgeleitete Funktionen
Die folgenden Funktionen bewegen den PlayerCharacter; die weitere Ausführung des Scripts wird unterbrochen. Diese Bewegung kann der Spieler durch Klicken mit der Maus abbrechen. Die Funktionen geben zurück, ob das Ziel erreicht oder abgebrochen wurde.
MovePlayer (int x, int y)
Bewegung auf Walkable Area zu den angegebene Koordinaten.
MovePlayerEx (int x, int y, int direct)
Mit direct = 1 werden Walkable Areas ignoriert. Der PlayerCharacter bewegt sich in gerader Linie zu den Koordinaten.
GoToCharacter (int charid, int direction, int NPCfacesplayer, int blocking)
Bewegt den PlayerCharacter zu charid, wobei Walkable Areas beachtet werden. Bleibt in einem definierten Abstand auf der Seite von charid stehen, die in direction (1=oberhalb/hinter, 2=rechts, 3=darunter/vor, 4=links) angegeben ist. Der PlayerCharacter schaut charid an. charid schaut den PlayerCharacter nur an, wenn NPCfacesplayer=1 ist. Für blocking können folgende Werte verwendet werden:
0=nicht blockierend (MoveCharacter)
1=blockierend (MoveCharacterBlocking)
2=halb-blockierend (MovePlayer)
Entsprechend gibt es eine Funktion, um eine NPC zu einem anderen Character zu bewegen: NPCGoToCharacter.
Eine allgemeine Funktion, um einen Character zu einem Character zu bewegen ist GoToCharacterEx. Bei dieser Funktion lässt sich auch der Abstand angeben, in dem die Figuren voneinander stehen sollen.
Es gibt auch zwei Funktionen, die den PlayerCharacter zu dem Hotspot, Object oder Character bewegen, auf die der Spieler geklickt hat: Go und GoTo. Nähere Erklärungen im global script.
e) PlaceCharacter und PlacePC
mit diesen Funktionen wird ein Character bzw. der PlayerCharacter an eine Stelle im Raum so platziert, dass er in eine bestimmte Richtung schaut. Einsatz in erster Linie in (... before fadein).
f) init_object (int GI, int objects)
Ist GlobalInt GI ==1, dann wird das Objekt objects angezeigt, ansonsten versteckt. Einsatz in erster Linie in (... before fadein).
(Fortsetzung folgt...)
-
- Süßwasserpirat
- Beiträge: 258
- Registriert: 22.09.2002, 21:28
- Kontaktdaten:
Hilfreiche Funktionen in MMM
a) Ein Hotpot oder Objekt, zu dem nur hingelaufen werden kann, für alle anderen Interactionen wird Unhandled aufgerufen:
Code: Alles auswählen
if (any_click_walk (x, y, dir) == 0) Unhandled ();
b) Ein Hotpot oder Objekt, das darüber hinaus angeschaut werden kann:
Code: Alles auswählen
if (any_click_walk_look (x, y, dir, lookat) == 0) Unhandled ();
c) Ein Objekt nehmen, das dann im Inventory erscheint:
Code: Alles auswählen
if (any_click_walk_look_pick (x, y, dir, lookat, objects, item, GI, sound) == 0) Unhandled ();
d) Ein InvItem mit dem Hotspot oder Objekt verwenden:
Code: Alles auswählen
if (any_click_walk_look (x, y, dir, lookat) == 0)
{
int result = any_click_use_inv (item, x, y, dir);
if (result == 0) Unhandled ();
if (result == 2)
{
// Script für das was passiert, wenn item verwendet wird
}
}
Türen können entweder zu, offen oder verschlossen sein. Manche können einfach so geöffnet werden, für andere braucht man einen Schlüssel. Diese Begriffe lassen sich auch umdefinieren: Ein Gartentor, das eingerostet ist und sich daher nicht einfach so öffnen lässt ist verschlossen. Der Schlüssel ist vielleicht ein Ölkännchen.
Grundsätzlich werden Türen im Hintergrund als geschlossen gezeichnet, ein darüber gelegtes Objekt zeigt die geöffnete Türe. Das Häkchen vor "Object is initially visible" wird entfernt, an die Bezeichnung der Türe in object name wird „>v“ angehängt.
Im global script in der game_start Funktion wird der Anfangszustand der Türe in einem GlobalInt gespeichert, hier z.B. GlobalInt 6:
a) Türe ist zu: SetGlobalInt (6, 0);
b) Türe ist offen: SetGlobalInt (6, 1);
c) Türe ist verschlossen: SetGlobalInt (6, 2);
Nun sind 2 Einträge im global script in der Funktion „VariableExtensions“ erforderlich.
Beispielsweise für eine Tür, deren Zustand in GlobalInt 6 gespeichert wird und zu der in Raum 2 der Hotspot 3 und in Raum 5 der Hotspot 2 gehört:
Code: Alles auswählen
else if ((r == 2) && (h == 3)) OpenCloseExtension (6, location);
else if ((r == 5) && (h == 2)) OpenCloseExtension (6, location);
Code: Alles auswählen
SetObjectClickable (4, 0);
init_object (6, 4);
In der „any click on hotspot“-Interaktion von Hotspot 3 in Raum 2 wird je nach gewünschter Öffnungsart eines der folgenden Scripts verwendet:
a) Normale Türe
Diese Türe lässt sich einfach von Hand öffnen und es ertönen die Standardsounds (2 beim Öffnen und 3 beim Schließen).
Code: Alles auswählen
if (any_click_on_door (6, 4, x, y, dir, 5, nr_x, nr_y, nr_dir) == 0) Unhandled ();
In diesem Fall sind 2 Zeilen erforderlich:
Code: Alles auswählen
SetDoorStrings („Dies ist eine Tür.“, „Die Tür ist verschlossen.“, „Damit geht die Tür nicht auf.“);
if (any_click_on_door_special (6, 4, x, y, dir, 5, nr_x, nr_y, nr_dir, opensound, closesound, key, closevalue) == 0) Unhandled ();
Die zweite Zeile ähnelt der Zeile bei der normalen Türe, allerdings können bspw. die Sounds angegeben werden. Mit key wird das InvItem bezeichnet, das die Türe öffnet, wenn sie verschlossen ist. Ist key=-1, dann kann die verschlossene Türe auch von Hand geöffnet werden. Wird eine offene Türe geschlossen, dann bezeichnet closevalue die Art: 0=zu, 2=verschlossen.
Bsp.: Verschlossene Tür
Die Tür kann in Raum 2 mit dem Schlüssel 7 aufgeschlossen werden, einmal aufgeschlossen, bleibt sie unverschlossen und kann künftig von Hand geöffnet werden.
Raum 2: Key = 7; closevalue = 0;
Raum 5: normale Tür
Bsp.: Haustüre
Zum Öffnen der Haustüre benötigt man in Raum 2 einen Schlüssel 7, in Raum 5 kann sie von Hand geöffnet werden:
Raum 2: Key = 7; closevalue = 2
Raum 5: Key = -1; closevalue = 2
Bsp.: Tür ist nur einseitig öffenbar, bspw. weil auf der anderen Seite kein Türgriff ist.
Raum 2: Key = -1; closevalue = 2
Raum 5: normale Tür
Bsp.: Eine automatische Tür mit Zahlenschloss
Bei Anklicken des Zahlenschlosses Hotspot 1 in Raum 2 springt die Tür auf.
In game_start wird die Tür als verschlossen angegeben:
Code: Alles auswählen
SetGlobalInt (6, 2);
Code: Alles auswählen
if (GetGlobalInt (6) != 1)
{
SetGlobalInt (6, 1);
PlaySound (2);
init_object (6, 4);
}
Code: Alles auswählen
if (GetGlobalInt (6) == 1)
{
SetGlobalInt (6, 2);
PlaySound (3);
init_object (6, 4);
}
-
- Adventure-Gott
- Beiträge: 4575
- Registriert: 13.07.2004, 14:04
- Wohnort: Da wo muss
- Kontaktdaten:
Die Tücken von MovePlayer
Die Funktion MovePlayer ist nicht dafür geeignet, den Spieler durch's Bild marschieren zu lassen. Dafür ist angebracht:
Code: Alles auswählen
MoveCharacterBlocking(GetPlayerCharacter(), x, y, 0); // Die 0 am Ende bedeutet, dass er Spieler auf den Walkable Areas bleibt
Code: Alles auswählen
player.Walk(x,y,eBlock,eWalkableAreas);
Ausnahmen bestätigen die Regel
_________________
<Problem> Weil du denken kannst.
Zuletzt bearbeitet von [ZENSIERT] am 16.07.1759, 16:19, insgesamt 54743869-mal bearbeitet
- KhrisMUC
- Adventure-Gott
- Beiträge: 4674
- Registriert: 14.03.2005, 00:55
- Wohnort: München
Wer in seiner Episode anderen Charakteren Inventargegenstände mit dem "Gib X an Y"-Befehl übergeben will, kann dies nun tun, ohne sich selber mit dem global script rumschlagen zu müssen bzw. Benutze zu verwenden:
Der entsprechende Teil in der on_mouse_click() muss so aussehen (zu erkennen an "else if ((GSagsusedmode == 4)"):
Code: Alles auswählen
else if ((GSagsusedmode == 4) && (GetLocationType (mouse.x, mouse.y) == 2) && isAction (A_GIVE_TO) && (GetCharacterAt (mouse.x, mouse.y) >= 0))
{
SetLabelColor (ACTION, 0, ActionLabelColorHighlighted);
if (IsInteractionAvailable (mrx - GetViewportX (), mry - GetViewportY (), MODE_USEINV) == 0)
player.Say("Ich werde das nicht ohne Grund hergeben.");
else if (GoToCharacter (GSlocid, 0, 1, 2))
{
ItemGiven = character [GetPlayerCharacter ()].activeinv;
RunCharacterInteraction (GSlocid, MODE_USEINV);
}
SetAction (A_DEFAULT);
}
Code: Alles auswählen
if (ItemGiven==7) {
player.Say("Hier, nimm den Luckenöffner(TM).");
LoseInventory(ItemGiven);
AddInventoryToCharacter(DAVE, ItemGiven);
cDave.Say("Danke.");
}
else {
player.Say("Kannst du das gebrauchen?");
cDave.Say("Nö.");
}
Bei Charakteren, bei denen nichts in Use inventory on character steht, läuft die Hauptperson nicht hin und sagt nur "Ich werde das nicht ohne Grund hergeben."
Hier kann man natürlich eine eigene Funktion aufrufen, die unterschiedliche/situationsangepasste Sätze ausgibt.
(Ich hätte es auch so scripten können, dass man bei any click on character mit "else if (UsedAction(A_GIVE_TO))" arbeiten kann, vielleicht ein andermal )
- KhrisMUC
- Adventure-Gott
- Beiträge: 4674
- Registriert: 14.03.2005, 00:55
- Wohnort: München
Im Tutorial gibt es Beispielcode für eine Lampe:
Code: Alles auswählen
if (UsedAction (A_WALK_TO)) {
if (MovePlayer (130, 133)) {
FaceLocation (GetPlayerCharacter (), 130, 132);
}
}
else if (UsedAction (A_LOOK_AT)) {
if (MovePlayer (130, 133)) {
FaceLocation (GetPlayerCharacter (), 130, 132);
DisplaySpeech (GetPlayerCharacter (), "Oha, die stand sonst nicht da.");
}
}
else if (UsedAction (A_PICK_UP)) {
if (MovePlayer (130, 133)) {
FaceLocation (GetPlayerCharacter (), 130, 132);
ObjectOff(6);
AddInventory(8);
}
}
else Unhandled ();
Code: Alles auswählen
if (MovePlayer (130, 133)) {
FaceDirection (GetPlayerCharacter (), DIR_UP); // EDIT: FaceDirection
if (UsedAction (A_WALK_TO)) {}
else if (UsedAction (A_LOOK_AT)) {
DisplaySpeech (GetPlayerCharacter (), "Oha, die stand sonst nicht da.");
}
else if (UsedAction (A_PICK_UP)) {
ObjectOff(6);
AddInventory(8);
}
else Unhandled ();
}
Zwar läuft jetzt der Charakter grundsätzlich erst zum Gegenstand hin, aber das ist IMO auch realistischer, gerade bei Unhandled()-Antworten wie "Ich kann das nicht öffnen."
EDIT: Genau, bitte einen Stickie draus machen. Vielleicht kann man auch einen Link zu diesem Thread ans Ende des Tutorials setzen.
EDIT [ZENSIERT]: Das kamma nochmal abkürzen
Code: Alles auswählen
if (MovePlayer (130, 133)) {
FaceDirection (GetPlayerCharacter (), DIR_UP);
if (UsedAction (A_LOOK_AT)) {
DisplaySpeech (GetPlayerCharacter (), "Oha, die stand sonst nicht da.");
}
else if (UsedAction (A_PICK_UP)) {
ObjectOff(6);
AddInventory(8);
}
else Unhandled ();
}
- Rocco
- Adventure-Treff
- Beiträge: 1019
- Registriert: 25.11.2003, 16:20
- Wohnort: Ronville
- Kontaktdaten:
Es geht um einen allgemeinen Bug, der sich bis jetzt hartnäckig in allen starterpacks gehalten hat, vorwiegend aber auch beim GIVE TO Befehl auftritt.
Und zwar wenn man eine Interaction mit einem anderen Character versucht und dabei ein Unhandled Event auslöst und man währendessen mit der Maus nicht mehr am Character ist, stürzt das Game ab mit einer Fehlermeldung - FaceCharacter kann nicht ausgeführt werden....
und zwar gibts in der Funktion unhandled_event nach dem grünen auskommentierten code so rund um zeile 2000 eine Zeile da steht:
Code: Alles auswählen
if (type == 2 || type == 6) FaceCharacter (GetPlayerCharacter (), GetCharacterAt (mouse.x, mouse.y));
diese ersetzen durch:
Code: Alles auswählen
if (type == 2 || type == 6)
{
if(GetLocationType(mouse.x,mouse.y)==2)
FaceCharacter (GetPlayerCharacter (), GetCharacterAt (mouse.x, mouse.y));
}
dann sollte der bug nicht mehr auftreten
- KhrisMUC
- Adventure-Gott
- Beiträge: 4674
- Registriert: 14.03.2005, 00:55
- Wohnort: München
Die Interaktionsskripte fangen ja normalerweise mit if (MovePlayer(x, y)) { ... an, der Vorteil hierbei ist, dass man durch erneuten Klick die momentane Aktion abbrechen kann abstatt darauf zu warten, dass man die Kontrolle zurückbekommt.
Soweit so gut, normalerweise klappt das ja auch einwandfrei.
Aber nehmen wir mal an, dass auf Grund gewisser Vorkommnisse im Spiel ein Gegenstand nicht mehr erreichbar ist, da eine walkable area abgeschaltet wurde.
Jetzt läuft der Spieler, bis er "anstößt" und führt dann trotzdem die Aktion aus.
Das liegt daran, dass MovePlayerEx auch 1 zurückliefert, wenn der Spieler nur stehengeblieben ist.
Am Ende sieht MovePlayerEx nämlich so aus:
Code: Alles auswählen
if (GScancelable == 0) return 1;
else return 0;
}
else return 0;
}
Code: Alles auswählen
if (GScancelable==0 && player.x==x && player.y==y) return 2;
else if (GScancelable == 0) return 1;
else return 0;
}
else return 0;
}
- Rocco
- Adventure-Treff
- Beiträge: 1019
- Registriert: 25.11.2003, 16:20
- Wohnort: Ronville
- Kontaktdaten:
Re: Hilfreiche Funktionen in MMM
http://www.maniac-mansion-mania.de/foru ... 9#msg36729