ich bastel grade an einem Mob (an einem oCMobInter um genau zu sein) der in einer Taverne oder einem Restaurant Verwendung finden soll. Es handelt sich um einen Tisch an dem der Spieler essen bestellen können soll. Ich hatte mir das so vorgestellt:
s0 --(Spieler setzt sich)--> s1
s1: Animationsschleife Spieler sitz nur am Tisch, mobsi-Dialog startet
Spieler bestellt Essen im mobsi-Dialog --(Essen erscheint bei ZS_LEFTHAND und ein Löffel bei ZS_RIGHTHAND)--> s2
s2: Animationsschleife Spieler isst sein bestelltes Essen.
In der Humans.mds sieht das dann so bei mir aus:
Code:
ani ("t_ESSTISCH_Stand_2_S0" 1 "s_ESSTISCH_S0" 0.2 0.0 M. "ESSTISCH_HUMAN_ANI_0_250.asc" F 0 4)
ani ("s_ESSTISCH_S0" 1 "s_ESSTISCH_S0" 0.0 0.0 M. "ESSTISCH_HUMAN_ANI_0_250.asc" F 5 5)
aniAlias ("t_ESSTISCH_S0_2_Stand" 1 "" 0.0 0.2 M. "t_ESSTISCH_Stand_2_S0" R)
ani ("t_ESSTISCH_S0_2_S1" 1 "s_ESSTISCH_S1" 0.0 0.0 M. "ESSTISCH_HUMAN_ANI_0_250.asc" F 5 41)
ani ("s_ESSTISCH_S1" 1 "s_ESSTISCH_S1" 0.0 0.0 MI "ESSTISCH_HUMAN_ANI_0_250.asc" F 42 95 FPS:10)
ani ("t_ESSTISCH_S1_2_S0" 1 "s_ESSTISCH_S0" 0.0 0.1 M. "ESSTISCH_HUMAN_ANI_0_250.asc" R 5 41)
{
*eventTag (41 "DEF_REMOVE_ITEM" "ZS_RIGHTHAND")
*eventTag (41 "DEF_REMOVE_ITEM" "ZS_LEFTHAND")
}
ani ("R_ESSTISCH_test" 1 "s_ESSTISCH_S2" 0.0 0.0 M. "ESSTISCH_HUMAN_ANI_0_250.asc" F 96 108)
{
*eventTag (96 "DEF_CREATE_ITEM" "ZS_RIGHTHAND" "ItMi_Loeffel")
*eventTag (96 "DEF_CREATE_ITEM" "ZS_LEFTHAND" "ItMi_Dish")
}
ani ("s_ESSTISCH_S2" 1 "s_ESSTISCH_S2" 0.0 0.0 MI "ESSTISCH_HUMAN_ANI_0_250.asc" F 109 207)
{
*eventMMStartAni (170 "T_EAT")
*eventSFX (170 "Eat_Meat" R:1000)
}
ani ("t_ESSTISCH_S2_2_S1" 1 "s_ESSTISCH_S1" 0.0 0.1 M. "ESSTISCH_HUMAN_ANI_0_250.asc" R 96 108)
Damit erst zum Zustand s2 übergegangen wird, wenn der Held auch sein Essen geordert hat gibt es keinen normalen Übergang "t_ESSTISCH_S1_2_S2", stattdessen gibt es die Animation "R_ESSTISCH_test", die vom mobsi-Dialog ausgeführt wird und in den Zustand s2 überführt:
Das mit den Animationen funktioniert soweit, jedoch bekommt der Held den Löffel und das Essen nicht in die Hand gedrückt. Ich habe schon eine Menge rumprobiert, aber ich bekomme es einfach nicht so hin, wie ich mir das gedacht hatte. Wahrscheinlich lässt sich das Problem mit LeGo lösen indem ich "oCNpc_PutInSlot" verwende um dem Held die Gegenstände in die Hand zu drücken, aber falls möglich würde ich gerne darauf verzichten, da ich mich nicht mit LeGo auskenne und den Mob auch ohne LeGo verwendbar machen will.
Hat jemand eine Idee, wie ich den mobsi umsetzen kann, ohne das dieses Problem mit dem in-die-Hand-nehmen auftritt?
Vielen Dank schonmal im Voraus
Hello,
(writing this in english, because my deutsch is not that good.)
you can invoke Mob state change with a engine function:
Code:
func void oCMobInter_SendStateChange (var int mobPtr, var int fromState, var int toState) {
//0x0067D8C0 protected: void __thiscall oCMobInter::SendStateChange(int,int)
const int oCMobInter__SendStateChange_G1 = 6805696;
//0x0071ED90 public: void __thiscall oCMobInter::SendStateChange(int,int)
const int oCMobInter__SendStateChange_G2 = 7466384;
if (!Hlp_Is_oCMobInter (mobPtr)) { return; };
const int call = 0;
if (CALL_Begin(call)) {
CALL_IntParam (_@ (toState));
CALL_IntParam (_@ (fromState));
CALL__thiscall (_@ (mobPtr), MEMINT_SwitchG1G2 (oCMobInter__SendStateChange_G1, oCMobInter__SendStateChange_G2));
call = CALL_End();
};
};
To use it, you jsut call it from your _INFO function:
Code:
var oCNpc slf; slf = Hlp_GetNPC (hero);
var int mobPtr; mobPtr = slf.interactMob;
oCMobInter_SendStateChange (mobPtr, 1, 2); // Change state from S1 to S2
Just create your states and their coresponding trasition animations and then use the oCMobInter_SendStateChange function, to switch between them.
In game it works looks like this. [Video]
Note: These are test animations, they are not supposed to work together, so it look kinda janky.
I attached the source files in a zip file, if you wish to study them
Wow, thank you so much for your quick reply.
It must have taken a lot of effort to create this example. I will try your solution and let you know if it worked.
Sadly your solution doesn't seem to solve the problem. The same issue still persists. The animation loop changes properly but using
"oCMobInter_SendStateChange (mobPtr, 1, 2)" to start the transition-animation:
Code:
ani ("t_ESSTISCH_S1_2_S2" 1 "s_ESSTISCH_S2" 0.0 0.0 M. "ESSTISCH_HUMAN_ANI_0_250.asc" F 96 108)
{
*eventTag (96 "DEF_CREATE_ITEM" "ZS_RIGHTHAND" "ItMi_Loeffel")
*eventTag (96 "DEF_CREATE_ITEM" "ZS_LEFTHAND" "ItMi_Dish")
}
prevents the items "ItMi_Loeffel" and "ItMi_Dish" from beeing spawned. It seems items can only be inserted or removed from the mobsi animation while starting or exiting the mobsi. I tested this with your statue mobsi and got the same results.
Sobald du per Skript dem Helden eine Animation oder einen derartigen Statechange aufzwingst, funktioniert das mit Def_Insert_item und def_remove_item etc. nicht mehr.
Es funktioniert nur, solange es ausschließlich über die Automatik der Mob-Interaktion läuft.
Der einzige derzeitige workaround sind die putinslot-Funktionen.
Das hatte ich befürchtet... naja, wie sich herausstellt gab es keinen Grund sich vor den "CALL__thiscall"-Funktionen zu fürchten, mit PutInSlot funktioniert alles Wunderbar!
Wie findet man eigentlich am besten die Adressen, die man benötigt? Ich habe dieses sehr hilfreiche gitlab Repository gefunden: https://gitlab.edfritsch.de:81/Christian/OpenGMP/-/tree/83089f9dce3c8ef169b1149a3f89576458cf97b7/OpenGMP/Gothic/Classes
Aber auch das scheint nicht alle Funktionen der Klassen zu beinhalten.
Wenn ich den Mob in einen zufriedenstellenden Zustand gebracht habe werde ich ihn in der Modderdatenbank hochladen.
Vielen Dank für eure Hilfe
Jetzt hat sich jedoch ein neues Problem ergeben. Ich wollte, dass der Held von einem Kellner angesprochen wird während er am Tisch sitzt und dann sein Essen bekommt, aber der Held steht dann immer sofort auf. Ich habe das auch mit Sitz-Mobs aus dem Original getestet und da passiert das selbe: Wenn der Held im sitzen in ein Gespräch verwickelt wird steht er auf. Ich hab etwas in "ZS_Talk" und "B_AssessTalk" rumprobiert, aber der Grund für das aufstehen des Helden scheint nicht dort zu liegen. Ich bin mir auch ziemlich sicher, dass das eigentlich nicht so gedacht ist, denn in "ZS_Talk" wird davon ausgegangen, dass der Spieler auch im Bodystate "BS_SIT" ein Gespräch führen kann, was so ja nicht möglich ist.
Weiß jemand eine Lösung, um das Aufstehen vom Mobsi zu verhindern?
PS: Selbstgespräche führen nicht dazu das der Held aufsteht, aber "AI_WaitTillEnd" tut es. Den Dialog nur vorzutäuschen ist also keine Option.
Super, danke Milky-Way, die Lösung funktioniert! Habs aber noch nicht ausführlich getestet.
Tut mir leid, dass ich den Thread nicht selbst gefunden habe. Ich hab wohl nach den falschen Schlagworten gesucht.
Der Held steht nun nicht mehr auf, wenn er während des Gesprächs auf seinen Gesprächspartner warten muss. Für den beschriebenen Zweck ist das auch vollkommen ausreichend, aber wenn er im Sitzen angequatscht wird, ploppt er immer noch hoch. Gibt es auch hierfür eine Möglichkeit dies zu unterbinden? Man könnte zum Beispiel einbauen, dass der Spieler angequatscht wird, wenn er sich an den Stammtisch des Statthalters setzt.
Benutzt du noch den original code in B_AssessTalk()?
Weil da gibt es weit unten im Block code, der den hero (other in dem Fall) aufstehen lässt einmal zu Beginn des Dialogs.
Vielen Dank Cryp18Struct! Ja, genau das war das Problem. Ich hatte die Stelle zwar schon mal geändert, aber weil das ohne die Lösung von Milky-Way zunächst nicht gewirkt hat, hatte ich den Ursprungszustand wieder hergestellt.
Leider bin ich schon wieder über ein Problem gestolpert, dass ich nicht gelöst bekomme. Nachdem der Dialog mit dem Kellner abgelaufen ist und ich die Dialog-Kamera abgestellt habe, würde ich gerne zur mobsi-Kamera bzw. zum Kamera-Preset "CamModMOBDefault" zurückkehren, aber die Kamera verharrt in der letzten Einstellung der Dialog-Kamera. Ich habe schon versucht:
Code:
zCAICamera__current = 9235128; //0x008CEAB8
entsprechend zu verändern, aber bisher ohne Erfolg. Ist das überhaupt der Richtige Ansatz?
Ich suche auch nach einem Weg, um Info-Blöcke hintereinander abzuspielen, ohne dass zuerst wieder eine Dialog-Option gewählt werden muss.
Du kannst info Blöcke wie jede andere Funktion auch aufrufen, glaube ich.
Im Prinzip natürlich schon, aber wenn man beispielsweis "PC_Table02_Info ()" einfach am Ende des vorherigen Info-Blocks aufruft, dann werden alle Funktionsaufrufe in "PC_Table02_Info ()" die nicht in einer AIQueue landen, schon zu Beginn des vorherigen Info-Blocks ausgeführt und genau das wollte ich verhindern, indem ich mehrere sukzessive Info-Blocke nehme. Ich bräuchte also sowas wie einen "important"-Info-Block, der mitten im Gespräch getriggert wird und nicht am Anfang.
Im Prinzip natürlich schon, aber wenn man beispielsweis "PC_Table02_Info ()" einfach am Ende des vorherigen Info-Blocks aufruft, dann werden alle Funktionsaufrufe in "PC_Table02_Info ()" die nicht in einer AIQueue landen, schon zu Beginn des vorherigen Info-Blocks ausgeführt und genau das wollte ich verhindern, indem ich mehrere sukzessive Info-Blocke nehme. Ich bräuchte also sowas wie einen "important"-Info-Block, der mitten im Gespräch getriggert wird und nicht am Anfang.
Mit LEGO ai_function kannst du den Aufruf einreihen.
Ich habe rausgefunden, dass man den gewünschten Effekt auch erzielen kann, indem man den Infoblock durch die ZS_Talk aufruft. Aber deine Lösung ist natürlich wesentlich sauberer, also werde ich das wohl nochmal ändern. Vielen Dank für den Tipp. Ihr seid echt Klasse!
Das mit der Kamera krieg ich bestimmt auch noch irgendwie hin.