Skip to content

Commit 8152826

Browse files
authored
New auto multilog interface (#33)
1 parent 4eda5d1 commit 8152826

File tree

5 files changed

+170
-39
lines changed

5 files changed

+170
-39
lines changed

_externals/zMultilogue.d

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,55 @@
44
//
55
// =========================================================
66

7-
/// Invites Npc to the Multilogue
7+
/// Invites NPC to the multilog.
88
///
9-
/// @param slf Npc to invite
10-
func void zMul_Invite(var C_NPC slf) {};
9+
/// @param npc NPC to invite
10+
func void zMul_Invite(var C_NPC npc) {};
1111

12-
/// Starts the Multilogue
12+
/// Starts the multilog.
1313
func void zMul_Start() {};
1414

15-
/// Changes talking NPC
15+
/// Changes talking NPC (must be invited first).
16+
/// TIP: When adding choices to the dialog, `self` is automatically set to the dialog owner, so you don't need to call this function before `Info_AddChoice()`.
1617
///
17-
/// @param slf Next talking NPC
18-
func void zMul_Next(var C_NPC slf) {};
18+
/// @global self will be set to the given NPC
19+
/// @param npc Next talking NPC
20+
func void zMul_Next(var C_NPC npc) {};
1921

20-
/// Finishes the Multilogue
22+
/// Finishes the multilog
23+
/// TIP: Since `v0.1.10`, when calling `AI_StopProcessInfos()` there is no need to call `zMul_Finish()`.
2124
func void zMul_Finish() {};
2225

23-
/// Makes invited NPC's wait for `slf` and each other
26+
/// Makes invited NPC's wait for `npc` and each other.
2427
///
25-
/// @param slf NPC to wait for
26-
func void zMul_Wait(var C_NPC slf) {};
28+
/// @param npc NPC to wait for
29+
func void zMul_Wait(var C_NPC npc) {};
2730

28-
/// Enables/disables auto-turning of the NPCs
29-
/// `talker`->`hero` and `hero`->`talker`
30-
/// @param autoTurn `1` = enabled, `0` = disabled
31-
func void zMul_AutoTurn(var int autoTurn) {};
32-
33-
/// Continues the Multilogue to the next dialog choice
34-
/// Call it instead of `zMul_Finish` if you want to continue the dialog
35-
/// Must be called before `Info_AddChoice`
31+
/// [deprecated] Continues the multilog to the next dialog choice.
32+
/// Must be called before `Info_AddChoice`.
3633
func void zMul_Continue() {};
3734

35+
/// Enables/disables automatic multilog mode, camera and NPC turning.
36+
///
37+
/// @param TRUE to enable, FALSE to disable
38+
func void zMul_Auto(var int enable) {};
39+
40+
/// Enables/disables automatic multilog mode.
41+
///
42+
/// @param TRUE to enable, FALSE to disable
43+
func void zMul_AutoMode(var int enable) {};
44+
45+
/// Enables/disables automatic NPC turning.
46+
/// NOTE: When enabled in manual mode, self and hero will be turning to each other.
47+
///
48+
/// @param TRUE to enable, FALSE to disable
49+
func void zMul_AutoTurn(var int enable) {};
50+
51+
/// Enables/disables automatic camera.
52+
///
53+
/// @param TRUE to enable, FALSE to disable
54+
func void zMul_AutoCam(var int enable) {};
55+
3856
// =========================================================
3957
//
4058
// Camera functions

src/Gothic/Externals.hpp

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -147,23 +147,56 @@ namespace GOTHIC_NAMESPACE {
147147
return 0;
148148
}
149149

150+
int zMul_Auto()
151+
{
152+
zCParser* par = zCParser::GetParser();
153+
int autoMode;
154+
par->GetParameter(autoMode);
155+
zMultilogue.SetAutoMode(autoMode != 0);
156+
zMultilogue.SetAutoTurn(autoMode != 0);
157+
zMultilogue.SetAutoCam(autoMode != 0);
158+
return 0;
159+
}
160+
161+
int zMul_AutoMode()
162+
{
163+
zCParser* par = zCParser::GetParser();
164+
int autoMode;
165+
par->GetParameter(autoMode);
166+
zMultilogue.SetAutoMode(autoMode != 0);
167+
return 0;
168+
}
169+
170+
int zMul_AutoCam()
171+
{
172+
zCParser* par = zCParser::GetParser();
173+
int autoCam;
174+
par->GetParameter(autoCam);
175+
zMultilogue.SetAutoCam(autoCam != 0);
176+
return 0;
177+
}
178+
150179
void DefineExternals()
151180
{
152-
parser->DefineExternal("ZMul_Invite", zMul_Invite, zPAR_TYPE_VOID, zPAR_TYPE_INSTANCE, zPAR_TYPE_VOID);
153-
parser->DefineExternal("ZMul_Start", zMul_Start, zPAR_TYPE_VOID, zPAR_TYPE_VOID);
154-
parser->DefineExternal("ZMul_Finish", zMul_Finish, zPAR_TYPE_VOID, zPAR_TYPE_VOID);
155-
parser->DefineExternal("ZMul_Next", zMul_Next, zPAR_TYPE_VOID, zPAR_TYPE_INSTANCE, zPAR_TYPE_VOID);
156-
parser->DefineExternal("ZMul_Wait", zMul_Wait, zPAR_TYPE_VOID, zPAR_TYPE_INSTANCE, zPAR_TYPE_VOID);
157-
parser->DefineExternal("ZMul_AutoTurn", zMul_AutoTurn, zPAR_TYPE_VOID, zPAR_TYPE_INT, zPAR_TYPE_VOID);
158-
parser->DefineExternal("ZMul_Continue", zMul_Continue, zPAR_TYPE_VOID, zPAR_TYPE_VOID);
181+
parser->DefineExternal("zMul_Invite", zMul_Invite, zPAR_TYPE_VOID, zPAR_TYPE_INSTANCE, zPAR_TYPE_VOID);
182+
parser->DefineExternal("zMul_Start", zMul_Start, zPAR_TYPE_VOID, zPAR_TYPE_VOID);
183+
parser->DefineExternal("zMul_Finish", zMul_Finish, zPAR_TYPE_VOID, zPAR_TYPE_VOID);
184+
parser->DefineExternal("zMul_Next", zMul_Next, zPAR_TYPE_VOID, zPAR_TYPE_INSTANCE, zPAR_TYPE_VOID);
185+
parser->DefineExternal("zMul_Wait", zMul_Wait, zPAR_TYPE_VOID, zPAR_TYPE_INSTANCE, zPAR_TYPE_VOID);
186+
parser->DefineExternal("zMul_Continue", zMul_Continue, zPAR_TYPE_VOID, zPAR_TYPE_VOID);
187+
188+
parser->DefineExternal("zMul_Auto", zMul_Auto, zPAR_TYPE_VOID, zPAR_TYPE_INT, zPAR_TYPE_VOID);
189+
parser->DefineExternal("zMul_AutoMode", zMul_AutoMode, zPAR_TYPE_VOID, zPAR_TYPE_INT, zPAR_TYPE_VOID);
190+
parser->DefineExternal("zMul_AutoTurn", zMul_AutoTurn, zPAR_TYPE_VOID, zPAR_TYPE_INT, zPAR_TYPE_VOID);
191+
parser->DefineExternal("zMul_AutoCam", zMul_AutoCam, zPAR_TYPE_VOID, zPAR_TYPE_INT, zPAR_TYPE_VOID);
159192

160-
parser->DefineExternal("ZMulCam_SetNpcs", zMulCam_SetNpcs, zPAR_TYPE_VOID, zPAR_TYPE_INSTANCE, zPAR_TYPE_INSTANCE, zPAR_TYPE_VOID);
161-
parser->DefineExternal("ZMulCam_SetTargetNpc", zMulCam_SetTargetNpc, zPAR_TYPE_VOID, zPAR_TYPE_INSTANCE, zPAR_TYPE_VOID);
162-
parser->DefineExternal("ZMulCam_SetSourceNpc", zMulCam_SetSourceNpc, zPAR_TYPE_VOID, zPAR_TYPE_INSTANCE, zPAR_TYPE_VOID);
163-
parser->DefineExternal("ZMulCam_SetTargetVob", zMulCam_SetTargetVob, zPAR_TYPE_VOID, zPAR_TYPE_STRING, zPAR_TYPE_VOID);
164-
parser->DefineExternal("ZMulCam_SetSourceVob", zMulCam_SetSourceVob, zPAR_TYPE_VOID, zPAR_TYPE_STRING, zPAR_TYPE_VOID);
165-
parser->DefineExternal("ZMulCam_SetMode", zMulCam_SetMode, zPAR_TYPE_VOID, zPAR_TYPE_INT, zPAR_TYPE_VOID);
166-
parser->DefineExternal("ZMulCam_Event", zMulCam_Event, zPAR_TYPE_VOID, zPAR_TYPE_VOID);
167-
parser->DefineExternal("ZMulCam_Reset", zMulCam_Reset, zPAR_TYPE_VOID, zPAR_TYPE_VOID);
193+
parser->DefineExternal("zMulCam_SetNpcs", zMulCam_SetNpcs, zPAR_TYPE_VOID, zPAR_TYPE_INSTANCE, zPAR_TYPE_INSTANCE, zPAR_TYPE_VOID);
194+
parser->DefineExternal("zMulCam_SetTargetNpc", zMulCam_SetTargetNpc, zPAR_TYPE_VOID, zPAR_TYPE_INSTANCE, zPAR_TYPE_VOID);
195+
parser->DefineExternal("zMulCam_SetSourceNpc", zMulCam_SetSourceNpc, zPAR_TYPE_VOID, zPAR_TYPE_INSTANCE, zPAR_TYPE_VOID);
196+
parser->DefineExternal("zMulCam_SetTargetVob", zMulCam_SetTargetVob, zPAR_TYPE_VOID, zPAR_TYPE_STRING, zPAR_TYPE_VOID);
197+
parser->DefineExternal("zMulCam_SetSourceVob", zMulCam_SetSourceVob, zPAR_TYPE_VOID, zPAR_TYPE_STRING, zPAR_TYPE_VOID);
198+
parser->DefineExternal("zMulCam_SetMode", zMulCam_SetMode, zPAR_TYPE_VOID, zPAR_TYPE_INT, zPAR_TYPE_VOID);
199+
parser->DefineExternal("zMulCam_Event", zMulCam_Event, zPAR_TYPE_VOID, zPAR_TYPE_VOID);
200+
parser->DefineExternal("zMulCam_Reset", zMulCam_Reset, zPAR_TYPE_VOID, zPAR_TYPE_VOID);
168201
}
169202
}

src/Gothic/Hooks.hpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ namespace GOTHIC_NAMESPACE {
5151
if (time>0.0f) ogame->GetCameraAI()->SetDialogCamDuration(time);
5252
auto mode = zSTRING("CAMMODDIALOG");
5353
ogame->GetCameraAI()->SetMode(mode, targetList);
54-
log->Info("Dialog camera activated. Source " + GetVobString(source) + " Target " + GetVobString(target));
54+
log->Info("Dialog camera activated. Mode: {0} Source - {1} Target - {2}", zMulCamera.GetMode(), GetVobString(source).ToChar() ,GetVobString(target).ToChar());
5555
return TRUE;
5656
}
5757
log->Warning("Source or target is not set.");
@@ -142,5 +142,21 @@ namespace GOTHIC_NAMESPACE {
142142
}
143143
(this->*Ivk_oCInformationManager_CollectInfos)();
144144
}
145+
146+
// AI_Output
147+
// G1: int __cdecl sub_6558F0()
148+
// G2A: int __cdecl sub_6E9F30()
149+
void __fastcall sub_6E9F30_PartialHook(Union::Registers& reg);
150+
auto Partial_sub_6E9F30 = Union::CreatePartialHook(reinterpret_cast<void*>(zSwitch(0x006558F0, 0x006E9F30)), &sub_6E9F30_PartialHook);
151+
void __fastcall sub_6E9F30_PartialHook(Union::Registers& reg)
152+
{
153+
if (zMultilogue.GetAutoMode())
154+
{
155+
// Call custom AI_Output function
156+
zMultilogue.AI_Output();
157+
// Skip original code
158+
reg.eip = zSwitch(0x00655B44, 0x006EA1BB); //endp
159+
}
160+
}
145161

146162
}

src/Gothic/zMul_Camera.hpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ namespace GOTHIC_NAMESPACE {
2121
void SetTarget(zCVob* target);
2222
void SetSource(zCVob* source);
2323
void SetMode(Mode mode);
24+
void SetModeInstant(Mode mode);
2425
void CameraEvent();
2526
void EV_SetTarget(zCVob* target);
2627
void EV_SetSource(zCVob* source);
@@ -38,14 +39,20 @@ namespace GOTHIC_NAMESPACE {
3839
player->GetEM()->OnMessage(msg, player);
3940
}
4041

42+
inline void zCMultilogueCamera::SetModeInstant(Mode mode)
43+
{
44+
static NH::Logger* log = NH::CreateLogger("zMul::zCMultilogueCamera::SetModeInstant");
45+
m_Mode = mode;
46+
log->Debug("Mode set to {0}", (int)mode);
47+
}
48+
4149
inline void zCMultilogueCamera::EV_SetMode(Mode mode)
4250
{
4351
static NH::Logger* log = NH::CreateLogger("zMul::zCMultilogueCamera::EV_SetMode");
4452
m_Mode = mode;
4553
log->Debug("Mode set to {0}", (int)mode);
4654
}
4755

48-
4956
inline void zCMultilogueCamera::SetSource(zCVob* source)
5057
{
5158
static NH::Logger* log = NH::CreateLogger("zMul::zCMultilogueCamera::SetSource");

src/Gothic/zMultilogue.hpp

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ namespace GOTHIC_NAMESPACE
1010
std::unordered_map<int, oCNpc*> m_Npcs;
1111
bool m_Running = false;
1212
bool m_AutoTurn = false;
13+
bool m_AutoMode = false;
14+
bool m_AutoCam = false;
1315
public:
1416
void AddNpc(oCNpc* npc);
1517
void Start();
@@ -24,6 +26,10 @@ namespace GOTHIC_NAMESPACE
2426
void Reset();
2527
void SetAutoTurn(bool autoTurn) { m_AutoTurn = autoTurn; }
2628
oCNpc* GetLastSelf() const { return m_LastSelf; }
29+
void AI_Output();
30+
void SetAutoMode(bool AutoMode) { m_AutoMode = AutoMode; }
31+
bool GetAutoMode() const { return m_AutoMode; }
32+
void SetAutoCam(bool AutoCam) { m_AutoCam = AutoCam; }
2733
};
2834

2935
static zCMultilogue zMultilogue = zCMultilogue{}; // Global instance
@@ -60,13 +66,15 @@ namespace GOTHIC_NAMESPACE
6066
log->Warning("Multilogue already running.");
6167
return;
6268
}
63-
m_AutoTurn = false;
69+
if (!m_AutoMode) {
70+
m_AutoTurn = false;
71+
}
6472
m_LastSelf = GetDialogOwner();
6573
AddNpc(player);
6674
AddNpc(m_LastSelf);
6775
m_Running = true;
6876
Wait(m_LastSelf);
69-
log->Info("Starting multilogue with {0} NPCs.", m_Npcs.size());
77+
log->Info("Starting {0}multilogue with {1} NPCs.", m_AutoMode ? "automatic " : "", m_Npcs.size());
7078
ListNpcs();
7179
}
7280

@@ -95,6 +103,7 @@ namespace GOTHIC_NAMESPACE
95103
oCMsgManipulate* msg = new oCMsgManipulate( oCMsgManipulate::EV_EXCHANGE);
96104
msg->slot = "EV_FINISH";
97105
player->GetEM()->OnMessage(msg, player);
106+
m_AutoMode = false;
98107
}
99108

100109

@@ -193,7 +202,7 @@ namespace GOTHIC_NAMESPACE
193202
}
194203
Wait(npc);
195204
// Self and player will turn to each other if m_AutoTurn is enabled
196-
if (m_AutoTurn) {
205+
if (m_AutoTurn && !m_AutoMode) {
197206
m_LastSelf->GetEM()->OnMessage(new oCMsgMovement(oCMsgMovement::EV_TURNTOVOB, player), m_LastSelf);
198207
player->GetEM()->OnMessage(new oCMsgMovement(oCMsgMovement::EV_TURNTOVOB, m_LastSelf), player);
199208
}
@@ -220,6 +229,54 @@ namespace GOTHIC_NAMESPACE
220229
m_LastSelf = nullptr;
221230
m_Npcs.clear();
222231
m_Running = false;
232+
m_AutoTurn = false;
233+
m_AutoMode = false;
234+
m_AutoCam = false;
223235
}
224236

237+
inline void zCMultilogue::AI_Output()
238+
{
239+
zCParser* par = zCParser::GetParser();
240+
zSTRING name;
241+
par->GetParameter(name);
242+
oCNpc* target = reinterpret_cast<oCNpc*>(par->GetInstance());
243+
oCNpc* talker = reinterpret_cast<oCNpc*>(par->GetInstance());
244+
if (target && talker) {
245+
if (!IsNpcInMultilogue(talker)) {
246+
AddNpc(talker);
247+
}
248+
if (!IsNpcInMultilogue(target)) {
249+
AddNpc(target);
250+
}
251+
if (!IsRunning()) {
252+
Start();
253+
}
254+
if (talker != player) {
255+
MakeSelf(talker);
256+
}
257+
if (m_AutoCam) {
258+
if (zMulCamera.GetMode() != zCMultilogueCamera::Mode::FULL) {
259+
zMulCamera.SetModeInstant(zCMultilogueCamera::Mode::FULL);
260+
}
261+
zMulCamera.SetTarget(talker);
262+
zMulCamera.SetSource(target);
263+
zMulCamera.CameraEvent();
264+
}
265+
if (m_AutoTurn) {
266+
talker->GetEM()->OnMessage(new oCMsgMovement(oCMsgMovement::EV_TURNTOVOB, target), talker);
267+
target->GetEM()->OnMessage(new oCMsgMovement(oCMsgMovement::EV_TURNTOVOB, talker), target);
268+
}
269+
Wait(talker);
270+
oCMsgConversation* msg = new oCMsgConversation(oCMsgConversation::EV_OUTPUT, name);
271+
if (talker != player) {
272+
msg->target = player;
273+
}
274+
else {
275+
msg->target = target;
276+
}
277+
talker->GetEM()->OnMessage(msg, talker);
278+
Wait(talker);
279+
}
280+
};
281+
225282
}

0 commit comments

Comments
 (0)