mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 06:53:58 +00:00
- Added Karate Chris's submission for multiplayer Strife conversations.
SVN r855 (trunk)
This commit is contained in:
parent
8d0c48bf81
commit
a01aaf35ad
10 changed files with 251 additions and 93 deletions
|
@ -33,6 +33,7 @@ March 25, 2008
|
||||||
the 2D panning area.
|
the 2D panning area.
|
||||||
|
|
||||||
March 25, 2008 (Changes by Graf Zahl)
|
March 25, 2008 (Changes by Graf Zahl)
|
||||||
|
- Added Karate Chris's submission for multiplayer Strife conversations.
|
||||||
- Increased the limit for 'imp/active' to 6. This sound definitely benefits
|
- Increased the limit for 'imp/active' to 6. This sound definitely benefits
|
||||||
from a higher limit.
|
from a higher limit.
|
||||||
- Fixed: $limit should not apply to sounds played from the menu.
|
- Fixed: $limit should not apply to sounds played from the menu.
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#include "a_sharedglobal.h"
|
#include "a_sharedglobal.h"
|
||||||
#include "st_start.h"
|
#include "st_start.h"
|
||||||
#include "teaminfo.h"
|
#include "teaminfo.h"
|
||||||
|
#include "p_conversation.h"
|
||||||
|
|
||||||
int P_StartScript (AActor *who, line_t *where, int script, char *map, bool backSide,
|
int P_StartScript (AActor *who, line_t *where, int script, char *map, bool backSide,
|
||||||
int arg0, int arg1, int arg2, int always, bool wantResultCode, bool net);
|
int arg0, int arg1, int arg2, int always, bool wantResultCode, bool net);
|
||||||
|
@ -2361,6 +2362,10 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DEM_CONVERSATION:
|
||||||
|
P_ConversationCommand (player, stream);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
I_Error ("Unknown net command: %d", type);
|
I_Error ("Unknown net command: %d", type);
|
||||||
break;
|
break;
|
||||||
|
@ -2451,6 +2456,31 @@ void Net_SkipCommand (int type, BYTE **stream)
|
||||||
skip = 3 + *(*stream + 2) * 4;
|
skip = 3 + *(*stream + 2) * 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DEM_CONVERSATION:
|
||||||
|
{
|
||||||
|
t = **stream;
|
||||||
|
skip = 1;
|
||||||
|
|
||||||
|
switch (t)
|
||||||
|
{
|
||||||
|
case CONV_ANIMATE:
|
||||||
|
skip += 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONV_GIVEINVENTORY:
|
||||||
|
skip += strlen ((char *)(*stream + skip)) + 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONV_TAKEINVENTORY:
|
||||||
|
skip += strlen ((char *)(*stream + skip)) + 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,6 +320,11 @@ public:
|
||||||
fixed_t crouchoffset;
|
fixed_t crouchoffset;
|
||||||
fixed_t crouchviewdelta;
|
fixed_t crouchviewdelta;
|
||||||
|
|
||||||
|
// [CW] I moved these here for multiplayer conversation support.
|
||||||
|
AActor *ConversationNPC, *ConversationPC;
|
||||||
|
angle_t ConversationNPCAngle;
|
||||||
|
bool ConversationFaceTalker;
|
||||||
|
|
||||||
fixed_t GetDeltaViewHeight() const
|
fixed_t GetDeltaViewHeight() const
|
||||||
{
|
{
|
||||||
return (mo->ViewHeight + crouchviewdelta - viewheight) >> 3;
|
return (mo->ViewHeight + crouchviewdelta - viewheight) >> 3;
|
||||||
|
|
|
@ -150,6 +150,7 @@ enum EDemoCommand
|
||||||
DEM_ADDCONTROLLER, // 48 Player to add to the controller list.
|
DEM_ADDCONTROLLER, // 48 Player to add to the controller list.
|
||||||
DEM_DELCONTROLLER, // 49 Player to remove from the controller list.
|
DEM_DELCONTROLLER, // 49 Player to remove from the controller list.
|
||||||
DEM_KILLCLASSCHEAT, // 50 String: Class to kill.
|
DEM_KILLCLASSCHEAT, // 50 String: Class to kill.
|
||||||
|
DEM_CONVERSATION, // 51 Make conversations work.
|
||||||
};
|
};
|
||||||
|
|
||||||
// The following are implemented by cht_DoCheat in m_cheat.cpp
|
// The following are implemented by cht_DoCheat in m_cheat.cpp
|
||||||
|
|
|
@ -81,6 +81,13 @@ public:
|
||||||
bool TryPickup (AActor *toucher);
|
bool TryPickup (AActor *toucher);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ASlideshowStarter : public ADummyStrifeItem
|
||||||
|
{
|
||||||
|
DECLARE_STATELESS_ACTOR (ASlideshowStarter, ADummyStrifeItem)
|
||||||
|
public:
|
||||||
|
bool TryPickup (AActor *toucher);
|
||||||
|
};
|
||||||
|
|
||||||
class AStrifeWeapon : public AWeapon
|
class AStrifeWeapon : public AWeapon
|
||||||
{
|
{
|
||||||
DECLARE_STATELESS_ACTOR (AStrifeWeapon, AWeapon)
|
DECLARE_STATELESS_ACTOR (AStrifeWeapon, AWeapon)
|
||||||
|
|
|
@ -514,13 +514,6 @@ bool AUpgradeAccuracy::TryPickup (AActor *toucher)
|
||||||
|
|
||||||
// Start a slideshow --------------------------------------------------------
|
// Start a slideshow --------------------------------------------------------
|
||||||
|
|
||||||
class ASlideshowStarter : public ADummyStrifeItem
|
|
||||||
{
|
|
||||||
DECLARE_STATELESS_ACTOR (ASlideshowStarter, ADummyStrifeItem)
|
|
||||||
public:
|
|
||||||
bool TryPickup (AActor *toucher);
|
|
||||||
};
|
|
||||||
|
|
||||||
IMPLEMENT_STATELESS_ACTOR (ASlideshowStarter, Strife, -1, 0)
|
IMPLEMENT_STATELESS_ACTOR (ASlideshowStarter, Strife, -1, 0)
|
||||||
PROP_StrifeType (343)
|
PROP_StrifeType (343)
|
||||||
END_DEFAULTS
|
END_DEFAULTS
|
||||||
|
|
|
@ -117,9 +117,8 @@ static void ConversationMenuEscaped ();
|
||||||
|
|
||||||
static FStrifeDialogueNode *CurNode, *PrevNode;
|
static FStrifeDialogueNode *CurNode, *PrevNode;
|
||||||
static FBrokenLines *DialogueLines;
|
static FBrokenLines *DialogueLines;
|
||||||
static AActor *ConversationNPC, *ConversationPC;
|
|
||||||
static angle_t ConversationNPCAngle;
|
static bool Conversation_TakeStuff;
|
||||||
static bool ConversationFaceTalker;
|
|
||||||
|
|
||||||
#define NUM_RANDOM_LINES 10
|
#define NUM_RANDOM_LINES 10
|
||||||
#define NUM_RANDOM_GOODBYES 3
|
#define NUM_RANDOM_GOODBYES 3
|
||||||
|
@ -571,14 +570,14 @@ static int FindNode (const FStrifeDialogueNode *node)
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
static bool CheckStrifeItem (const PClass *itemtype, int amount=-1)
|
static bool CheckStrifeItem (player_t *player, const PClass *itemtype, int amount=-1)
|
||||||
{
|
{
|
||||||
AInventory *item;
|
AInventory *item;
|
||||||
|
|
||||||
if (itemtype == NULL || amount == 0)
|
if (itemtype == NULL || amount == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
item = ConversationPC->FindInventory (itemtype);
|
item = player->ConversationPC->FindInventory (itemtype);
|
||||||
if (item == NULL)
|
if (item == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -594,7 +593,7 @@ static bool CheckStrifeItem (const PClass *itemtype, int amount=-1)
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
static void TakeStrifeItem (const PClass *itemtype, int amount)
|
static void TakeStrifeItem (player_t *player, const PClass *itemtype, int amount)
|
||||||
{
|
{
|
||||||
if (itemtype == NULL || amount == 0)
|
if (itemtype == NULL || amount == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -611,15 +610,10 @@ static void TakeStrifeItem (const PClass *itemtype, int amount)
|
||||||
if (itemtype == RUNTIME_CLASS(ASigil))
|
if (itemtype == RUNTIME_CLASS(ASigil))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AInventory *item = ConversationPC->FindInventory (itemtype);
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
if (item != NULL)
|
Net_WriteByte (CONV_TAKEINVENTORY);
|
||||||
{
|
Net_WriteString (itemtype->TypeName.GetChars ());
|
||||||
item->Amount -= amount;
|
Net_WriteWord (amount);
|
||||||
if (item->Amount <= 0)
|
|
||||||
{
|
|
||||||
item->Destroy ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
|
CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
|
||||||
|
@ -633,7 +627,6 @@ CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
|
||||||
// P_StartConversation
|
// P_StartConversation
|
||||||
//
|
//
|
||||||
// Begins a conversation between a PC and NPC.
|
// Begins a conversation between a PC and NPC.
|
||||||
// FIXME: Make this work in multiplayer.
|
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
|
@ -645,14 +638,22 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
||||||
const char *toSay;
|
const char *toSay;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
|
// [CW] If an NPC is talking to a PC already, then don't let
|
||||||
|
// anyone else talk to NPC.
|
||||||
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (!playeringame[i] || pc->player == &players[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (npc == players[i].ConversationNPC)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pc->momx = pc->momy = 0; // Stop moving
|
pc->momx = pc->momy = 0; // Stop moving
|
||||||
pc->player->momx = pc->player->momy = 0;
|
pc->player->momx = pc->player->momy = 0;
|
||||||
|
|
||||||
if (pc->player - players != consoleplayer)
|
pc->player->ConversationPC = pc;
|
||||||
return;
|
pc->player->ConversationNPC = npc;
|
||||||
|
|
||||||
ConversationPC = pc;
|
|
||||||
ConversationNPC = npc;
|
|
||||||
|
|
||||||
CurNode = npc->Conversation;
|
CurNode = npc->Conversation;
|
||||||
|
|
||||||
|
@ -662,10 +663,10 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
||||||
}
|
}
|
||||||
|
|
||||||
npc->reactiontime = 2;
|
npc->reactiontime = 2;
|
||||||
ConversationFaceTalker = facetalker;
|
pc->player->ConversationFaceTalker = facetalker;
|
||||||
if (saveangle)
|
if (saveangle)
|
||||||
{
|
{
|
||||||
ConversationNPCAngle = npc->angle;
|
pc->player->ConversationNPCAngle = npc->angle;
|
||||||
}
|
}
|
||||||
oldtarget = npc->target;
|
oldtarget = npc->target;
|
||||||
npc->target = pc;
|
npc->target = pc;
|
||||||
|
@ -682,11 +683,11 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
||||||
// Check if we should jump to another node
|
// Check if we should jump to another node
|
||||||
while (CurNode->ItemCheck[0] != NULL)
|
while (CurNode->ItemCheck[0] != NULL)
|
||||||
{
|
{
|
||||||
if (CheckStrifeItem (CurNode->ItemCheck[0]) &&
|
if (CheckStrifeItem (pc->player, CurNode->ItemCheck[0]) &&
|
||||||
CheckStrifeItem (CurNode->ItemCheck[1]) &&
|
CheckStrifeItem (pc->player, CurNode->ItemCheck[1]) &&
|
||||||
CheckStrifeItem (CurNode->ItemCheck[2]))
|
CheckStrifeItem (pc->player, CurNode->ItemCheck[2]))
|
||||||
{
|
{
|
||||||
int root = FindNode (ConversationNPC->GetDefault()->Conversation);
|
int root = FindNode (pc->player->ConversationNPC->GetDefault()->Conversation);
|
||||||
CurNode = StrifeDialogues[root + CurNode->ItemCheckNode - 1];
|
CurNode = StrifeDialogues[root + CurNode->ItemCheckNode - 1];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -697,10 +698,13 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
||||||
|
|
||||||
if (CurNode->SpeakerVoice != 0)
|
if (CurNode->SpeakerVoice != 0)
|
||||||
{
|
{
|
||||||
I_SetMusicVolume(dlg_musicvolume);
|
I_SetMusicVolume (dlg_musicvolume);
|
||||||
S_SoundID (npc, CHAN_VOICE|CHAN_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM);
|
S_SoundID (npc, CHAN_VOICE|CHAN_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pc->player != &players[consoleplayer])
|
||||||
|
return;
|
||||||
|
|
||||||
// Set up the menu
|
// Set up the menu
|
||||||
ConversationMenu.PreDraw = DrawConversationMenu;
|
ConversationMenu.PreDraw = DrawConversationMenu;
|
||||||
ConversationMenu.EscapeHandler = ConversationMenuEscaped;
|
ConversationMenu.EscapeHandler = ConversationMenuEscaped;
|
||||||
|
@ -786,9 +790,17 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
||||||
|
|
||||||
void P_ResumeConversation ()
|
void P_ResumeConversation ()
|
||||||
{
|
{
|
||||||
if (ConversationPC != NULL && ConversationNPC != NULL)
|
for (int i = 0; i < MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
P_StartConversation (ConversationNPC, ConversationPC, ConversationFaceTalker, false);
|
if (!playeringame[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
player_t *p = &players[i];
|
||||||
|
|
||||||
|
if (p->ConversationPC != NULL && p->ConversationNPC != NULL)
|
||||||
|
{
|
||||||
|
P_StartConversation (p->ConversationNPC, p->ConversationPC, p->ConversationFaceTalker, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -803,6 +815,8 @@ static void DrawConversationMenu ()
|
||||||
const char *speakerName;
|
const char *speakerName;
|
||||||
int i, x, y, linesize;
|
int i, x, y, linesize;
|
||||||
|
|
||||||
|
player_t *cp = &players[consoleplayer];
|
||||||
|
|
||||||
assert (DialogueLines != NULL);
|
assert (DialogueLines != NULL);
|
||||||
assert (CurNode != NULL);
|
assert (CurNode != NULL);
|
||||||
|
|
||||||
|
@ -812,7 +826,8 @@ static void DrawConversationMenu ()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ConversationPauseTic < gametic)
|
// [CW] Pausing the game in a multiplayer game is a bad idea.
|
||||||
|
if (ConversationPauseTic < gametic && !multiplayer)
|
||||||
{
|
{
|
||||||
menuactive = MENU_On;
|
menuactive = MENU_On;
|
||||||
}
|
}
|
||||||
|
@ -832,7 +847,7 @@ static void DrawConversationMenu ()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
speakerName = ConversationNPC->GetClass()->Meta.GetMetaString (AMETA_StrifeName);
|
speakerName = cp->ConversationNPC->GetClass()->Meta.GetMetaString (AMETA_StrifeName);
|
||||||
if (speakerName == NULL)
|
if (speakerName == NULL)
|
||||||
{
|
{
|
||||||
speakerName = "Person";
|
speakerName = "Person";
|
||||||
|
@ -873,7 +888,7 @@ static void DrawConversationMenu ()
|
||||||
|
|
||||||
if (ShowGold)
|
if (ShowGold)
|
||||||
{
|
{
|
||||||
AInventory *coin = ConversationPC->FindInventory (RUNTIME_CLASS(ACoin));
|
AInventory *coin = cp->ConversationPC->FindInventory (RUNTIME_CLASS(ACoin));
|
||||||
char goldstr[32];
|
char goldstr[32];
|
||||||
|
|
||||||
sprintf (goldstr, "%d", coin != NULL ? coin->Amount : 0);
|
sprintf (goldstr, "%d", coin != NULL ? coin->Amount : 0);
|
||||||
|
@ -892,94 +907,89 @@ static void DrawConversationMenu ()
|
||||||
//
|
//
|
||||||
// PickConversationReply
|
// PickConversationReply
|
||||||
//
|
//
|
||||||
// FIXME: Make this work in multiplayer
|
|
||||||
//
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
static void PickConversationReply ()
|
static void PickConversationReply ()
|
||||||
{
|
{
|
||||||
const char *replyText = NULL;
|
const char *replyText = NULL;
|
||||||
FStrifeDialogueReply *reply = (FStrifeDialogueReply *)ConversationItems[ConversationMenu.lastOn].c.extra;
|
FStrifeDialogueReply *reply = (FStrifeDialogueReply *)ConversationItems[ConversationMenu.lastOn].c.extra;
|
||||||
bool takestuff;
|
|
||||||
int i;
|
int i;
|
||||||
|
player_t *cp = &players[consoleplayer];
|
||||||
|
|
||||||
|
Conversation_TakeStuff = false;
|
||||||
|
|
||||||
M_ClearMenus ();
|
M_ClearMenus ();
|
||||||
CleanupConversationMenu ();
|
CleanupConversationMenu ();
|
||||||
if (reply == NULL)
|
if (reply == NULL)
|
||||||
{
|
{
|
||||||
ConversationNPC->angle = ConversationNPCAngle;
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
|
Net_WriteByte (CONV_NPCANGLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if you have the requisite items for this choice
|
// Check if you have the requisite items for this choice
|
||||||
for (i = 0; i < 3; ++i)
|
for (i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
if (!CheckStrifeItem (reply->ItemCheck[i], reply->ItemCheckAmount[i]))
|
if (!CheckStrifeItem (cp, reply->ItemCheck[i], reply->ItemCheckAmount[i]))
|
||||||
{
|
{
|
||||||
// No, you don't. Say so and let the NPC animate negatively.
|
// No, you don't. Say so and let the NPC animate negatively.
|
||||||
if (reply->QuickNo)
|
if (reply->QuickNo)
|
||||||
{
|
{
|
||||||
Printf ("%s\n", reply->QuickNo);
|
Printf ("%s\n", reply->QuickNo);
|
||||||
}
|
}
|
||||||
ConversationNPC->ConversationAnimation (2);
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
ConversationNPC->angle = ConversationNPCAngle;
|
Net_WriteByte (CONV_ANIMATE);
|
||||||
|
Net_WriteByte (2);
|
||||||
|
|
||||||
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
|
Net_WriteByte (CONV_NPCANGLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yay, you do! Let the NPC animate affirmatively.
|
// Yay, you do! Let the NPC animate affirmatively.
|
||||||
ConversationNPC->ConversationAnimation (1);
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
|
Net_WriteByte (CONV_ANIMATE);
|
||||||
|
Net_WriteByte (1);
|
||||||
|
|
||||||
// If this reply gives you something, then try to receive it.
|
// If this reply gives you something, then try to receive it.
|
||||||
takestuff = true;
|
Conversation_TakeStuff = true;
|
||||||
if (reply->GiveType != NULL)
|
if (reply->GiveType != NULL)
|
||||||
{
|
{
|
||||||
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
||||||
{
|
{
|
||||||
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
||||||
{
|
{
|
||||||
if (players[consoleplayer].mo->FindInventory(reply->GiveType) != NULL)
|
if (cp->mo->FindInventory(reply->GiveType) != NULL)
|
||||||
{
|
{
|
||||||
takestuff = false;
|
Conversation_TakeStuff = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (takestuff)
|
if (Conversation_TakeStuff)
|
||||||
{
|
{
|
||||||
AInventory *item = static_cast<AInventory *> (Spawn (reply->GiveType, 0, 0, 0, NO_REPLACE));
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
// Items given here should not count as items!
|
Net_WriteByte (CONV_GIVEINVENTORY);
|
||||||
if (item->flags & MF_COUNTITEM)
|
Net_WriteString (reply->GiveType->TypeName.GetChars ());
|
||||||
{
|
|
||||||
level.total_items--;
|
|
||||||
item->flags &= ~MF_COUNTITEM;
|
|
||||||
}
|
|
||||||
if (item->IsA(RUNTIME_CLASS(AFlameThrower)))
|
|
||||||
{
|
|
||||||
// The flame thrower gives less ammo when given in a dialog
|
|
||||||
static_cast<AWeapon*>(item)->AmmoGive1 = 40;
|
|
||||||
}
|
|
||||||
item->flags |= MF_DROPPED;
|
|
||||||
if (!item->TryPickup (players[consoleplayer].mo))
|
|
||||||
{
|
|
||||||
item->Destroy ();
|
|
||||||
takestuff = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reply->GiveType->IsDescendantOf (RUNTIME_CLASS (ASlideshowStarter)))
|
||||||
|
gameaction = ga_slideshow;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Trying to give a non-inventory item.
|
// Trying to give a non-inventory item.
|
||||||
takestuff = false;
|
Conversation_TakeStuff = false;
|
||||||
Printf("Attempting to give non-inventory item %s\n", reply->GiveType->TypeName.GetChars());
|
Printf("Attempting to give non-inventory item %s\n", reply->GiveType->TypeName.GetChars());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take away required items if the give was successful or none was needed.
|
// Take away required items if the give was successful or none was needed.
|
||||||
if (takestuff)
|
if (Conversation_TakeStuff)
|
||||||
{
|
{
|
||||||
for (i = 0; i < 3; ++i)
|
for (i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
TakeStrifeItem (reply->ItemCheck[i], reply->ItemCheckAmount[i]);
|
TakeStrifeItem (&players[consoleplayer], reply->ItemCheck[i], reply->ItemCheckAmount[i]);
|
||||||
}
|
}
|
||||||
replyText = reply->QuickYes;
|
replyText = reply->QuickYes;
|
||||||
}
|
}
|
||||||
|
@ -991,7 +1001,7 @@ static void PickConversationReply ()
|
||||||
// Update the quest log, if needed.
|
// Update the quest log, if needed.
|
||||||
if (reply->LogNumber != 0)
|
if (reply->LogNumber != 0)
|
||||||
{
|
{
|
||||||
players[consoleplayer].SetLogNumber (reply->LogNumber);
|
cp->SetLogNumber (reply->LogNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replyText != NULL)
|
if (replyText != NULL)
|
||||||
|
@ -1000,32 +1010,43 @@ static void PickConversationReply ()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does this reply alter the speaker's conversation node? If NextNode is positive,
|
// Does this reply alter the speaker's conversation node? If NextNode is positive,
|
||||||
// the next time they talk, the will show the new node. If it is negative, then they
|
// the next time they talk, they will show the new node. If it is negative, then they
|
||||||
// will show the new node right away without terminating the dialogue.
|
// will show the new node right away without terminating the dialogue.
|
||||||
if (reply->NextNode != 0)
|
if (reply->NextNode != 0)
|
||||||
{
|
{
|
||||||
int rootnode = FindNode (ConversationNPC->GetDefault()->Conversation);
|
int rootnode = FindNode (cp->ConversationNPC->GetDefault()->Conversation);
|
||||||
if (reply->NextNode < 0)
|
if (reply->NextNode < 0)
|
||||||
{
|
{
|
||||||
ConversationNPC->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1];
|
cp->ConversationNPC->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1];
|
||||||
if (gameaction != ga_slideshow)
|
if (gameaction != ga_slideshow)
|
||||||
{
|
{
|
||||||
P_StartConversation (ConversationNPC, players[consoleplayer].mo, ConversationFaceTalker, false);
|
P_StartConversation (cp->ConversationNPC, cp->mo, cp->ConversationFaceTalker, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
S_StopSound (ConversationNPC, CHAN_VOICE);
|
S_StopSound (cp->ConversationNPC, CHAN_VOICE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ConversationNPC->Conversation = StrifeDialogues[rootnode + reply->NextNode - 1];
|
cp->ConversationNPC->Conversation = StrifeDialogues[rootnode + reply->NextNode - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConversationNPC->angle = ConversationNPCAngle;
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
I_SetMusicVolume(1.f);
|
Net_WriteByte (CONV_NPCANGLE);
|
||||||
|
|
||||||
|
// [CW] Set these to NULL because we're not talking to them
|
||||||
|
// anymore. However, this can interfere with slideshows so
|
||||||
|
// we don't set them to NULL in that case.
|
||||||
|
if (gameaction != ga_slideshow)
|
||||||
|
{
|
||||||
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
|
Net_WriteByte (CONV_SETNULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
I_SetMusicVolume (1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
@ -1058,19 +1079,96 @@ void CleanupConversationMenu ()
|
||||||
DialogueLines = NULL;
|
DialogueLines = NULL;
|
||||||
}
|
}
|
||||||
ConversationItems.Clear ();
|
ConversationItems.Clear ();
|
||||||
I_SetMusicVolume(1.f);
|
I_SetMusicVolume (1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
//
|
//
|
||||||
// ConversationMenuEscaped
|
// ConversationMenuEscaped
|
||||||
//
|
//
|
||||||
// Called when the user presses escape to leave tho conversation menu.
|
// Called when the user presses escape to leave the conversation menu.
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
void ConversationMenuEscaped ()
|
void ConversationMenuEscaped ()
|
||||||
{
|
{
|
||||||
CleanupConversationMenu ();
|
CleanupConversationMenu ();
|
||||||
ConversationNPC->angle = ConversationNPCAngle;
|
|
||||||
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
|
Net_WriteByte (CONV_NPCANGLE);
|
||||||
|
|
||||||
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
|
Net_WriteByte (CONV_SETNULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// P_ConversationCommand
|
||||||
|
//
|
||||||
|
// Complete a conversation command.
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
void P_ConversationCommand (int player, BYTE **stream)
|
||||||
|
{
|
||||||
|
int type = ReadByte (stream);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case CONV_NPCANGLE:
|
||||||
|
players[player].ConversationNPC->angle = players[player].ConversationNPCAngle;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONV_ANIMATE:
|
||||||
|
players[player].ConversationNPC->ConversationAnimation (ReadByte (stream));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONV_GIVEINVENTORY:
|
||||||
|
{
|
||||||
|
AInventory *item = static_cast<AInventory *> (Spawn (ReadString (stream), 0, 0, 0, NO_REPLACE));
|
||||||
|
// Items given here should not count as items!
|
||||||
|
if (item->flags & MF_COUNTITEM)
|
||||||
|
{
|
||||||
|
level.total_items--;
|
||||||
|
item->flags &= ~MF_COUNTITEM;
|
||||||
|
}
|
||||||
|
if (item->IsA(RUNTIME_CLASS(AFlameThrower)))
|
||||||
|
{
|
||||||
|
// The flame thrower gives less ammo when given in a dialog
|
||||||
|
static_cast<AWeapon*>(item)->AmmoGive1 = 40;
|
||||||
|
}
|
||||||
|
item->flags |= MF_DROPPED;
|
||||||
|
if (!item->TryPickup (players[player].mo))
|
||||||
|
{
|
||||||
|
item->Destroy ();
|
||||||
|
Conversation_TakeStuff = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONV_TAKEINVENTORY:
|
||||||
|
{
|
||||||
|
AInventory *item = players[player].ConversationPC->FindInventory (PClass::FindClass (ReadString (stream)));
|
||||||
|
|
||||||
|
if (item != NULL)
|
||||||
|
{
|
||||||
|
item->Amount -= ReadWord (stream);
|
||||||
|
if (item->Amount <= 0)
|
||||||
|
{
|
||||||
|
item->Destroy ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONV_SETNULL:
|
||||||
|
players[player].ConversationFaceTalker = NULL;
|
||||||
|
players[player].ConversationNPC = NULL;
|
||||||
|
players[player].ConversationPC = NULL;
|
||||||
|
players[player].ConversationNPCAngle = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
// users can edit as simple text files. Particularly useful would be
|
// users can edit as simple text files. Particularly useful would be
|
||||||
// the ability to call ACS functions to implement AppearsWhen properties
|
// the ability to call ACS functions to implement AppearsWhen properties
|
||||||
// and ACS scripts to implement ActionTaken properties.
|
// and ACS scripts to implement ActionTaken properties.
|
||||||
// TODO: Make this work in multiplayer and in demos. Multiplayer probably
|
// TODO: Make this work in demos.
|
||||||
// isn't possible for Strife conversations, but demo playback should be.
|
|
||||||
|
|
||||||
struct FStrifeDialogueReply;
|
struct FStrifeDialogueReply;
|
||||||
class FTexture;
|
class FTexture;
|
||||||
|
@ -48,6 +47,16 @@ struct FStrifeDialogueReply
|
||||||
FBrokenLines *ReplyLines;
|
FBrokenLines *ReplyLines;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// [CW] These are used to make conversations work.
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CONV_NPCANGLE,
|
||||||
|
CONV_ANIMATE,
|
||||||
|
CONV_GIVEINVENTORY,
|
||||||
|
CONV_TAKEINVENTORY,
|
||||||
|
CONV_SETNULL,
|
||||||
|
};
|
||||||
|
|
||||||
extern TArray<FStrifeDialogueNode *> StrifeDialogues;
|
extern TArray<FStrifeDialogueNode *> StrifeDialogues;
|
||||||
|
|
||||||
// There were 344 types in Strife, and Strife conversations refer
|
// There were 344 types in Strife, and Strife conversations refer
|
||||||
|
@ -62,4 +71,6 @@ void P_FreeStrifeConversations ();
|
||||||
void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveangle);
|
void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveangle);
|
||||||
void P_ResumeConversation ();
|
void P_ResumeConversation ();
|
||||||
|
|
||||||
|
void P_ConversationCommand (int player, BYTE **stream);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -281,7 +281,11 @@ player_s::player_s()
|
||||||
crouchdir(0),
|
crouchdir(0),
|
||||||
crouchfactor(0),
|
crouchfactor(0),
|
||||||
crouchoffset(0),
|
crouchoffset(0),
|
||||||
crouchviewdelta(0)
|
crouchviewdelta(0),
|
||||||
|
ConversationNPC(0),
|
||||||
|
ConversationPC(0),
|
||||||
|
ConversationNPCAngle(0),
|
||||||
|
ConversationFaceTalker(0)
|
||||||
{
|
{
|
||||||
memset (&cmd, 0, sizeof(cmd));
|
memset (&cmd, 0, sizeof(cmd));
|
||||||
memset (&userinfo, 0, sizeof(userinfo));
|
memset (&userinfo, 0, sizeof(userinfo));
|
||||||
|
@ -315,6 +319,8 @@ size_t player_s::FixPointers (const DObject *old, DObject *rep)
|
||||||
if (last_mate == old) last_mate = replacement, changed++;
|
if (last_mate == old) last_mate = replacement, changed++;
|
||||||
if (ReadyWeapon == old) ReadyWeapon = static_cast<AWeapon *>(rep), changed++;
|
if (ReadyWeapon == old) ReadyWeapon = static_cast<AWeapon *>(rep), changed++;
|
||||||
if (PendingWeapon == old) PendingWeapon = static_cast<AWeapon *>(rep), changed++;
|
if (PendingWeapon == old) PendingWeapon = static_cast<AWeapon *>(rep), changed++;
|
||||||
|
if (ConversationNPC == old) ConversationNPC = replacement, changed++;
|
||||||
|
if (ConversationPC == old) ConversationPC = replacement, changed++;
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,6 +337,8 @@ size_t player_s::PropagateMark()
|
||||||
GC::Mark(mate);
|
GC::Mark(mate);
|
||||||
GC::Mark(last_mate);
|
GC::Mark(last_mate);
|
||||||
GC::Mark(ReadyWeapon);
|
GC::Mark(ReadyWeapon);
|
||||||
|
GC::Mark(ConversationNPC);
|
||||||
|
GC::Mark(ConversationPC);
|
||||||
if (PendingWeapon != WP_NOCHANGE)
|
if (PendingWeapon != WP_NOCHANGE)
|
||||||
{
|
{
|
||||||
GC::Mark(PendingWeapon);
|
GC::Mark(PendingWeapon);
|
||||||
|
@ -2419,7 +2427,11 @@ void player_s::Serialize (FArchive &arc)
|
||||||
<< BlendB
|
<< BlendB
|
||||||
<< BlendA
|
<< BlendA
|
||||||
<< accuracy << stamina
|
<< accuracy << stamina
|
||||||
<< LogText;
|
<< LogText
|
||||||
|
<< ConversationNPC
|
||||||
|
<< ConversationPC
|
||||||
|
<< ConversationNPCAngle
|
||||||
|
<< ConversationFaceTalker;
|
||||||
|
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
arc << frags[i];
|
arc << frags[i];
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
// Version identifier for network games.
|
// Version identifier for network games.
|
||||||
// Bump it every time you do a release unless you're certain you
|
// Bump it every time you do a release unless you're certain you
|
||||||
// didn't change anything that will affect sync.
|
// didn't change anything that will affect sync.
|
||||||
#define NETGAMEVERSION 215
|
#define NETGAMEVERSION 216
|
||||||
|
|
||||||
// Version stored in the ini's [LastRun] section.
|
// Version stored in the ini's [LastRun] section.
|
||||||
// Bump it if you made some configuration change that you want to
|
// Bump it if you made some configuration change that you want to
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
// Protocol version used in demos.
|
// Protocol version used in demos.
|
||||||
// Bump it if you change existing DEM_ commands or add new ones.
|
// Bump it if you change existing DEM_ commands or add new ones.
|
||||||
// Otherwise, it should be safe to leave it alone.
|
// Otherwise, it should be safe to leave it alone.
|
||||||
#define DEMOGAMEVERSION 0x20B
|
#define DEMOGAMEVERSION 0x20C
|
||||||
|
|
||||||
// Minimum demo version we can play.
|
// Minimum demo version we can play.
|
||||||
// Bump it whenever you change or remove existing DEM_ commands.
|
// Bump it whenever you change or remove existing DEM_ commands.
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
// SAVESIG should match SAVEVER.
|
// SAVESIG should match SAVEVER.
|
||||||
|
|
||||||
// MINSAVEVER is the minimum level snapshot version that can be loaded.
|
// MINSAVEVER is the minimum level snapshot version that can be loaded.
|
||||||
#define MINSAVEVER 849
|
#define MINSAVEVER 854
|
||||||
|
|
||||||
#if SVN_REVISION_NUMBER < MINSAVEVER
|
#if SVN_REVISION_NUMBER < MINSAVEVER
|
||||||
// Never write a savegame with a version lower than what we need
|
// Never write a savegame with a version lower than what we need
|
||||||
|
|
Loading…
Reference in a new issue