- Consolidated all conversation reply handling into a single function executed on all

machines, so when an NPC need to show the "enough" response, it has enough
  information available to do so.
- Some new Strife Teaser fixes I forgot to commit are in here.
- Moved norawinput check into FindRawInputFunctions().


SVN r2120 (trunk)
This commit is contained in:
Randy Heit 2010-01-22 05:17:57 +00:00
parent d547e89548
commit 71b75f0d7a
9 changed files with 558 additions and 557 deletions

View file

@ -283,11 +283,11 @@ static EIWADType ScanIWAD (const char *iwad)
}
else if (lumpsfound[Check_invcurs])
{
return IWAD_StrifeTeaser2;
return IWAD_StrifeTeaser2; // Strife0.wad from 14 Mar 1996
}
else
{
return IWAD_StrifeTeaser;
return IWAD_StrifeTeaser; // Strife0.wad from 22 Feb 1996
}
}
else if (lumpsfound[Check_map01])

View file

@ -1046,7 +1046,10 @@ void D_DoStrifeAdvanceDemo ()
pagetic = 7 * TICRATE;
pagename = "PANEL1";
S_Sound (CHAN_VOICE | CHAN_UI, voices[0], 1, ATTN_NORM);
S_StartMusic ("d_intro");
// The new Strife teaser has D_FMINTR.
// The full retail Strife has D_INTRO.
// And the old Strife teaser has both. (I do not know which one it actually uses, nor do I care.)
S_StartMusic (gameinfo.flags & GI_TEASER2 ? "d_fmintr" : "d_intro");
break;
case 4:

View file

@ -2367,8 +2367,10 @@ void Net_DoCommand (int type, BYTE **stream, int player)
}
break;
case DEM_CONVERSATION:
P_ConversationCommand (player, stream);
case DEM_CONVREPLY:
case DEM_CONVCLOSE:
case DEM_CONVNULL:
P_ConversationCommand (type, player, stream);
break;
case DEM_SETSLOT:
@ -2500,29 +2502,8 @@ void Net_SkipCommand (int type, BYTE **stream)
skip = 3 + *(*stream + 2) * 4;
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;
}
}
case DEM_CONVREPLY:
skip = 3;
break;
case DEM_SETSLOT:

View file

@ -147,14 +147,17 @@ enum EDemoCommand
DEM_ADDCONTROLLER, // 48 Player to add to the controller list.
DEM_DELCONTROLLER, // 49 Player to remove from the controller list.
DEM_KILLCLASSCHEAT, // 50 String: Class to kill.
DEM_CONVERSATION, // 51 Make conversations work.
DEM_UNDONE11, // 51
DEM_SUMMON2, // 52 String: Thing to fabricate, WORD: angle offset
DEM_SUMMONFRIEND2, // 53
DEM_SUMMONFOE2, // 54
DEM_ADDSLOTDEFAULT, // 55
DEM_ADDSLOT, // 56
DEM_SETSLOT, // 57
DEM_SUMMONMBF,
DEM_SUMMONMBF, // 58
DEM_CONVREPLY, // 59 Word: Dialogue node, Byte: Reply number
DEM_CONVCLOSE, // 60
DEM_CONVNULL, // 61
};
// The following are implemented by cht_DoCheat in m_cheat.cpp

View file

@ -125,8 +125,6 @@ static void ConversationMenuEscaped ();
static FStrifeDialogueNode *CurNode, *PrevNode;
static FBrokenLines *DialogueLines;
static bool Conversation_TakeStuff;
#define NUM_RANDOM_LINES 10
#define NUM_RANDOM_GOODBYES 3
@ -282,7 +280,7 @@ static void LoadScriptFile(FileReader *lump, int numnodes)
{
node = ReadTeaserNode (lump, prevSpeakerType);
}
StrifeDialogues.Push (node);
node->ThisNodeNum = StrifeDialogues.Push(node);
}
}
@ -623,18 +621,23 @@ static void TakeStrifeItem (player_t *player, const PClass *itemtype, int amount
if (itemtype->IsDescendantOf (PClass::FindClass(NAME_QuestItem)))
return;
// Don't take keys
// Don't take keys.
if (itemtype->IsDescendantOf (RUNTIME_CLASS(AKey)))
return;
// Don't take the sigil
// Don't take the sigil.
if (itemtype == RUNTIME_CLASS(ASigil))
return;
Net_WriteByte (DEM_CONVERSATION);
Net_WriteByte (CONV_TAKEINVENTORY);
Net_WriteString (itemtype->TypeName.GetChars ());
Net_WriteWord (amount);
AInventory *item = player->mo->FindInventory (itemtype);
if (item != NULL)
{
item->Amount -= amount;
if (item->Amount <= 0)
{
item->Destroy ();
}
}
}
CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
@ -732,7 +735,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
}
// Set up the menu
::CurNode = CurNode; // only set the global variaböle for the consoleplayer
::CurNode = CurNode; // only set the global variable for the consoleplayer
ConversationMenu.PreDraw = DrawConversationMenu;
ConversationMenu.EscapeHandler = ConversationMenuEscaped;
@ -743,10 +746,13 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
FString dlgtext;
dlgtext.Format("TXT_%s_%02d", toSay, 1+(pr_randomspeech() % NUM_RANDOM_LINES));
toSay = GStrings[dlgtext.GetChars()];
if (toSay==NULL) toSay = "Go away!"; // Ok, it's lame - but it doesn't look like an error to the player. ;)
toSay = GStrings[dlgtext];
if (toSay == NULL)
{
toSay = "Go away!"; // Ok, it's lame - but it doesn't look like an error to the player. ;)
}
}
DialogueLines = V_BreakLines (SmallFont, screen->GetWidth()/CleanXfac-24*2, toSay);
DialogueLines = V_BreakLines (SmallFont, screen->GetWidth()/CleanXfac - 24*2, toSay);
// Fill out the possible choices
ShowGold = false;
@ -980,93 +986,155 @@ static bool DrawConversationMenu ()
//
// PickConversationReply
//
// Run only on the local machine with the conversation menu up.
//
//============================================================================
static void PickConversationReply ()
{
const char *replyText = NULL;
FStrifeDialogueReply *reply = (FStrifeDialogueReply *)ConversationItems[ConversationMenu.lastOn].c.extra;
int i;
player_t *cp = &players[consoleplayer];
FStrifeDialogueReply *replyscan;
int replynum = 0;
Conversation_TakeStuff = false;
assert(CurNode->ThisNodeNum >= 0 && CurNode->ThisNodeNum < 65536);
assert(StrifeDialogues[CurNode->ThisNodeNum] == CurNode);
M_ClearMenus ();
CleanupConversationMenu ();
// Determine reply number for netcode.
if (reply == NULL)
{
Net_WriteByte (DEM_CONVERSATION);
Net_WriteByte (CONV_NPCANGLE);
Net_WriteByte (DEM_CONVERSATION);
Net_WriteByte (CONV_CLOSE);
replyscan = NULL;
}
else
{
for (replyscan = CurNode->Children; replyscan != NULL && replyscan != reply; ++replynum, replyscan = replyscan->Next)
{ }
}
M_ClearMenus ();
if (replyscan == NULL)
{
Net_WriteByte(DEM_CONVCLOSE);
}
else
{
// Send dialogue and reply numbers across the wire.
assert(replynum < 256);
Net_WriteByte(DEM_CONVREPLY);
Net_WriteWord(CurNode->ThisNodeNum);
Net_WriteByte(replynum);
}
CleanupConversationMenu ();
}
//============================================================================
//
// HandleReply
//
// Run by the netcode on all machines.
//
//============================================================================
static void HandleReply(player_t *player, bool isconsole, int nodenum, int replynum)
{
const char *replyText = NULL;
FStrifeDialogueReply *reply;
FStrifeDialogueNode *node;
AActor *npc;
bool takestuff;
int i;
if (player->ConversationNPC == NULL || (unsigned)nodenum >= StrifeDialogues.Size())
{
return;
}
// Find the reply.
node = StrifeDialogues[nodenum];
for (i = 0, reply = node->Children; reply != NULL && i != replynum; ++i, reply = reply->Next)
{ }
if (reply == NULL)
{
return;
}
npc = player->ConversationNPC;
// Check if you have the requisite items for this choice
for (i = 0; i < 3; ++i)
{
if (!CheckStrifeItem (cp, reply->ItemCheck[i], reply->ItemCheckAmount[i]))
if (!CheckStrifeItem(player, reply->ItemCheck[i], reply->ItemCheckAmount[i]))
{
// No, you don't. Say so and let the NPC animate negatively.
if (reply->QuickNo)
if (reply->QuickNo && isconsole)
{
Printf ("%s\n", reply->QuickNo);
Printf("%s\n", reply->QuickNo);
}
Net_WriteByte (DEM_CONVERSATION);
Net_WriteByte (CONV_ANIMATE);
Net_WriteByte (2);
Net_WriteByte (DEM_CONVERSATION);
Net_WriteByte (CONV_NPCANGLE);
Net_WriteByte (DEM_CONVERSATION);
Net_WriteByte (CONV_CLOSE);
npc->ConversationAnimation(2);
npc->angle = player->ConversationNPCAngle;
npc->flags5 &= ~MF5_INCONVERSATION;
return;
}
}
// Yay, you do! Let the NPC animate affirmatively.
Net_WriteByte (DEM_CONVERSATION);
Net_WriteByte (CONV_ANIMATE);
Net_WriteByte (1);
npc->ConversationAnimation(1);
// If this reply gives you something, then try to receive it.
Conversation_TakeStuff = true;
takestuff = true;
if (reply->GiveType != NULL)
{
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AInventory)))
{
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
{
if (cp->mo->FindInventory(reply->GiveType) != NULL)
if (player->mo->FindInventory(reply->GiveType) != NULL)
{
Conversation_TakeStuff = false;
takestuff = false;
}
}
if (Conversation_TakeStuff)
if (takestuff)
{
Net_WriteByte (DEM_CONVERSATION);
Net_WriteByte (CONV_GIVEINVENTORY);
Net_WriteString (reply->GiveType->TypeName.GetChars ());
AInventory *item = static_cast<AInventory *>(Spawn(reply->GiveType, 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->GetClass()->TypeName == NAME_FlameThrower)
{
// The flame thrower gives less ammo when given in a dialog
static_cast<AWeapon*>(item)->AmmoGive1 = 40;
}
item->flags |= MF_DROPPED;
if (!item->CallTryPickup(player->mo))
{
item->Destroy();
takestuff = false;
}
}
if (reply->GiveType->IsDescendantOf (RUNTIME_CLASS (ASlideshowStarter)))
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(ASlideshowStarter)))
gameaction = ga_slideshow;
}
else
{
// Trying to give a non-inventory item.
Conversation_TakeStuff = false;
Printf("Attempting to give non-inventory item %s\n", reply->GiveType->TypeName.GetChars());
takestuff = false;
if (isconsole)
{
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.
if (Conversation_TakeStuff)
if (takestuff)
{
for (i = 0; i < 3; ++i)
{
TakeStrifeItem (&players[consoleplayer], reply->ItemCheck[i], reply->ItemCheckAmount[i]);
TakeStrifeItem (player, reply->ItemCheck[i], reply->ItemCheckAmount[i]);
}
replyText = reply->QuickYes;
}
@ -1078,12 +1146,12 @@ static void PickConversationReply ()
// Update the quest log, if needed.
if (reply->LogNumber != 0)
{
cp->SetLogNumber (reply->LogNumber);
player->SetLogNumber(reply->LogNumber);
}
if (replyText != NULL)
if (replyText != NULL && isconsole)
{
Printf ("%s\n", replyText);
Printf("%s\n", replyText);
}
// Does this reply alter the speaker's conversation node? If NextNode is positive,
@ -1091,39 +1159,44 @@ static void PickConversationReply ()
// will show the new node right away without terminating the dialogue.
if (reply->NextNode != 0)
{
int rootnode = FindNode (cp->ConversationNPC->GetDefault()->Conversation);
int rootnode = FindNode (npc->GetDefault()->Conversation);
if (reply->NextNode < 0)
{
cp->ConversationNPC->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1];
npc->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1];
if (gameaction != ga_slideshow)
{
P_StartConversation (cp->ConversationNPC, cp->mo, cp->ConversationFaceTalker, false);
P_StartConversation (npc, player->mo, player->ConversationFaceTalker, false);
return;
}
else
{
S_StopSound (cp->ConversationNPC, CHAN_VOICE);
S_StopSound (npc, CHAN_VOICE);
}
}
else
{
cp->ConversationNPC->Conversation = StrifeDialogues[rootnode + reply->NextNode - 1];
npc->Conversation = StrifeDialogues[rootnode + reply->NextNode - 1];
}
}
Net_WriteByte (DEM_CONVERSATION);
Net_WriteByte (CONV_NPCANGLE);
npc->angle = player->ConversationNPCAngle;
// [CW] Set these to NULL because we're not using 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);
npc->flags5 &= ~MF5_INCONVERSATION;
player->ConversationFaceTalker = false;
player->ConversationNPC = NULL;
player->ConversationPC = NULL;
player->ConversationNPCAngle = 0;
}
I_SetMusicVolume (1.f);
if (isconsole)
{
I_SetMusicVolume (1.f);
}
}
//============================================================================
@ -1170,12 +1243,7 @@ void CleanupConversationMenu ()
void ConversationMenuEscaped ()
{
CleanupConversationMenu ();
Net_WriteByte (DEM_CONVERSATION);
Net_WriteByte (CONV_NPCANGLE);
Net_WriteByte (DEM_CONVERSATION);
Net_WriteByte (CONV_SETNULL);
Net_WriteByte (DEM_CONVNULL);
}
//============================================================================
@ -1186,77 +1254,30 @@ void ConversationMenuEscaped ()
//
//============================================================================
void P_ConversationCommand (int player, BYTE **stream)
void P_ConversationCommand (int netcode, int pnum, BYTE **stream)
{
int type = ReadByte (stream);
player_t *player = &players[pnum];
switch (type)
if (netcode == DEM_CONVREPLY)
{
case CONV_NPCANGLE:
players[player].ConversationNPC->angle = players[player].ConversationNPCAngle;
break;
case CONV_ANIMATE:
players[player].ConversationNPC->ConversationAnimation (ReadByte (stream));
break;
case CONV_GIVEINVENTORY:
int nodenum = ReadWord(stream);
int replynum = ReadByte(stream);
HandleReply(player, pnum == consoleplayer, nodenum, replynum);
}
else
{
assert(netcode == DEM_CONVNULL || netcode == DEM_CONVCLOSE);
if (player->ConversationNPC != NULL)
{
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->GetClass()->TypeName == NAME_FlameThrower)
{
// The flame thrower gives less ammo when given in a dialog
static_cast<AWeapon*>(item)->AmmoGive1 = 40;
}
item->flags |= MF_DROPPED;
if (!item->CallTryPickup (players[player].mo))
{
item->Destroy ();
Conversation_TakeStuff = false;
}
player->ConversationNPC->angle = player->ConversationNPCAngle;
player->ConversationNPC->flags5 &= ~MF5_INCONVERSATION;
}
break;
case CONV_TAKEINVENTORY:
if (netcode == DEM_CONVNULL)
{
AInventory *item = players[player].ConversationPC->FindInventory (PClass::FindClass (ReadString (stream)));
if (item != NULL)
{
item->Amount -= ReadWord (stream);
if (item->Amount <= 0)
{
item->Destroy ();
}
}
player->ConversationFaceTalker = false;
player->ConversationNPC = NULL;
player->ConversationPC = NULL;
player->ConversationNPCAngle = 0;
}
break;
case CONV_SETNULL:
if (players[player].ConversationNPC != NULL)
{
players[player].ConversationNPC->flags5 &= ~MF5_INCONVERSATION;
}
players[player].ConversationFaceTalker = false;
players[player].ConversationNPC = NULL;
players[player].ConversationPC = NULL;
players[player].ConversationNPCAngle = 0;
break;
case CONV_CLOSE:
if (players[player].ConversationNPC != NULL)
{
players[player].ConversationNPC->flags5 &= ~MF5_INCONVERSATION;
}
break;
default:
break;
}
}

View file

@ -17,6 +17,7 @@ struct FStrifeDialogueNode
~FStrifeDialogueNode ();
const PClass *DropType;
const PClass *ItemCheck[3];
int ThisNodeNum; // location of this node in StrifeDialogues
int ItemCheckNode; // index into StrifeDialogues
const PClass *SpeakerType;
@ -47,17 +48,6 @@ struct FStrifeDialogueReply
FBrokenLines *ReplyLines;
};
// [CW] These are used to make conversations work.
enum
{
CONV_NPCANGLE,
CONV_ANIMATE,
CONV_GIVEINVENTORY,
CONV_TAKEINVENTORY,
CONV_SETNULL,
CONV_CLOSE,
};
extern TArray<FStrifeDialogueNode *> StrifeDialogues;
// There were 344 types in Strife, and Strife conversations refer
@ -74,6 +64,6 @@ void P_FreeStrifeConversations ();
void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveangle);
void P_ResumeConversation ();
void P_ConversationCommand (int player, BYTE **stream);
void P_ConversationCommand (int netcode, int player, BYTE **stream);
#endif

View file

@ -64,11 +64,11 @@
// Protocol version used in demos.
// Bump it if you change existing DEM_ commands or add new ones.
// Otherwise, it should be safe to leave it alone.
#define DEMOGAMEVERSION 0x212
#define DEMOGAMEVERSION 0x213
// Minimum demo version we can play.
// Bump it whenever you change or remove existing DEM_ commands.
#define MINDEMOVERSION 0x211
#define MINDEMOVERSION 0x213
// SAVEVER is the version of the information stored in level snapshots.
// Note that SAVEVER is not directly comparable to VERSION.

View file

@ -598,7 +598,7 @@ bool I_InitInput (void *hwnd)
g_pdi = NULL;
g_pdi3 = NULL;
if (!norawinput) FindRawInputFunctions();
FindRawInputFunctions();
// Try for DirectInput 8 first, then DirectInput 3 for NT 4's benefit.
DInputDLL = LoadLibrary("dinput8.dll");
@ -938,13 +938,16 @@ bool FInputDevice::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP
static void FindRawInputFunctions()
{
HMODULE user32 = GetModuleHandle("user32.dll");
if (user32 == NULL)
if (!norawinput)
{
return; // WTF kind of broken system are we running on?
}
HMODULE user32 = GetModuleHandle("user32.dll");
if (user32 == NULL)
{
return; // WTF kind of broken system are we running on?
}
#define RIF(name,ret,args) \
My##name = (name##Proto)GetProcAddress(user32, #name);
My##name = (name##Proto)GetProcAddress(user32, #name);
#include "rawinput.h"
}
}

File diff suppressed because it is too large Load diff