Sprites, textures, sounds, code, and other resources belong here. Share and share-alike!
Forum rules
Before posting your Resource, please make sure you can answer YES to any of the following questions:
Is the resource ENTIRELY my own work?
If no to the previous one, do I have permission from the original author?
If no to the previous one, did I put a reasonable amount of work into the resource myself, such that the changes are noticeably different from the source that I could take credit for them?
If you answered no to all three, maybe you should consider taking your stuff somewhere other than the Resources forum.
When I re-worked the conversation menus for Blade of Agony and realized quite how hard-coded everything was, I decided to try to make a more "modder-friendly" interface to the conversation menus.
I'm honestly not sure if this is the "best" way to do this, and I'm sure it can be improved, but this certainly makes it easier for me to set up a customized conversation interface... So I figured I should share.
(Additional text added just to make sure to show the scrollbar)
Essentially, I've created a descriptor class that holds conversation-scope variables and settings and an array of the dialogue controls that are added. I created generic dialogue components with a standard set of attributes that can be managed from one inherited class, instead of having to duplicate and modify each part of the existing menu code every time I want a new configuration.
Spoiler: Example code for the interface in the screenshot
If I want to create the conversation menu that's shown above, I inherit from ExtendedConversationMenuBase and use this code...
class SampleConversationMenu : ExtendedConversationMenuBase
{
//This still relies on some of the old ConversationMenu parsing code under the hood
override int Init(StrifeDialogueNode CurNode, PlayerInfo player, int activereply)
{
//Set some default values
Super.Init(CurNode, player, activereply);
//Used below to align speaker name/text and responses
// Assumes default dialogue coordinate system
// (e.g., dialogue.targetscreenx = 320 and dialogue.targetscreeny = 240)
int xAlign = 74;
int yAlign = 16;
int width = 216;
dialogue = new("DialogueDescriptor"); // New dialogue "container" - essentially for dialogue-scope variables and keeping track of all of the dialogue components
dialogue.currentmenu = self; // Required here because an Init is called early in the Response code below, otherwise it would be set via the dialogue.Init call at the bottom
dialogue.focus = "Responses"; // Set initial focus - overridden if there's a scrolling text element
dialogue.autofocus = true; // When true, automatically moves between tabindexed elements when you reach the end of a scrollable area (text or response list)
dialogue.selectiondim.alpha = 0.2; // Dim the backgroud of the currently active control
dialogue.selectiondim.clr = 0x332211;
let Background = dialogue.AddNew("DialogueBackground");
Background.image = "CONVBACK";
Background.dim.alpha = 0.25;
Background.alpha = 0.75;
let Icon = dialogue.AddNew("DialogueIcon");
Icon.image = mCurNode.Backdrop;
Icon.h = 38;
Icon.w = 38;
Icon.pos.x = int(xAlign - 10 - Icon.w);
Icon.pos.y = yAlign;
Icon.margin.left = 1;
Icon.margin.right = 1;
Icon.margin.top = 1;
Icon.margin.bottom = 1;
Icon.dim.alpha = 0.45;
let SpeakerName = dialogue.AddNew("DialogueTextBox");
SpeakerName.scale = 0.5;
SpeakerName.SetFont = "BigFont";
SpeakerName.fontcolor = Font.CR_GOLD;
SpeakerName.caption = ParseSpeakerName();
SpeakerName.w = width;
SpeakerName.pos.x = xAlign;
SpeakerName.pos.y = yAlign;
let Responses = dialogue.AddNew("DialogueResponses");
Responses.scale = 0.7;
Responses.fontcolor = Font.CR_UNTRANSLATED;
Responses.linespacing = 1.5;
Responses.w = width;
Responses.refname = "Responses";
Responses.pos.x = xAlign;
Responses.margin.top = 2;
Responses.margin.bottom = 2;
Responses.margin.left = 2;
Responses.margin.right = 2;
Responses.dim.alpha = 0.45;
Responses.numberformat = "%d. ";
Responses.numberwidth = 16;
Responses.tabindex = 2;
Responses.numberalign = ALIGN_Right;
ParseReplies(int(Responses.w / Responses.scale)); //ParseReplies is still basically the old parsing code - TODO: Redo more generically...
Responses.Init(); // Early direct call to Init to automatically calculate height based on response line count
Responses.pos.y = 225 - Responses.h; // 'h' calculated during Init call
let SpeakerText = dialogue.AddNew("DialogueTextBox");
SpeakerText.linespacing = 2.0;
SpeakerText.caption = ParseSpeakerMessage();
SpeakerText.refname = "SpeakerText";
SpeakerText.pos.x = xAlign;
SpeakerText.pos.y = yAlign + 16;
SpeakerText.w = width;
SpeakerText.h = Responses.pos.y - 8 - SpeakerText.pos.y; // Fills screen down to just above response block
SpeakerText.margin.top = 2;
SpeakerText.margin.bottom = 2;
SpeakerText.margin.left = 2;
SpeakerText.margin.right = 2;
SpeakerText.scale = 0.75;
SpeakerText.tabindex = 1;
SpeakerText.textalign = ALIGN_Center;
dialogue.Initialize(self);
return 100; // y value on screen where output messages will appear (e.g., "You seem to have enough")
}
}
There are some non-intuitive bits, but for the most part the variable names are self-explanatory (and commented in the base .txt file).
Things this adds beyond the capabilities of the original code:
- Individual "controls" support font selection and scaling (see above: speaker name is BigFont at 0.5 scale, text is SmallFont - the default - at 0.75 scale)
- Supports setting the default x/y coordinate resolution for control placement - defaults to a 320x240 resolution
- Instead of CONFONT, uses graphics for response selector arrow (will probably add another bool to make this optional in future for standardization)
- If a textbox has content longer than it can hold, a scrollbar is automatically added (uses graphics similar to the selector arrow's)
-- Scrollbar is mouse- and mousewheel-enabled (click and drag handle, click arrows or scrollabr area, scroll mousewheel when textbox is active, etc.)
- Tab and Shift+Tab can be used to navigate between items with a 'tabindex' value set
- Navigation between controls can also be set to automatically happen (e.g., if you scroll down to the end of a textbox, selection will automatically move to next tabindexed control)
- Background dim for selected control can be modified (alpha and color), and margins can be set to control how far out from the control get dimmed.
- New CVars via CVARINFO that can be customized by the modder to govern what I termed as the "active", "inactive", and "alternate" color for the graphical dialogue components
-- In the shot above, the up arrow on the scroll bar is inactive (because the text box is scroll all the way up), the down arrow is active (because there's more to scroll to in that direction)
-- The scroll handle is alternate and the selector arrow swaps between alternate and inactive color and between two graphics.
- Text alignment (left/right/center) for textboxes and responses. In the example, speaker text is centered, replies are left aligned, and reply numbers are right aligned.
Download Sample (based on BoA's new conversation code layout that Tormentor667 mocked up). Easiest way to see this in action is to run it in Strife and go talk to someone.
Cool...just perfect. But one question: Does this work with the 'stock' conversation functions, like "conversation, name, dialogue", or do I have to learn new functions?
EDIT: Yes, it of course works with stock vonversation controls. Just sweet.
Last edited by ramon.dexter on Sat Mar 11, 2017 7:29 am, edited 1 time in total.
Brilliant work AFA, I am pretty sure that people will be very happy having a better conversation system on their hands Maybe this would even be interesting to be added to the Realm667 repo... the question is just: Where? Maybe we'd need a new category called "ZScript" for that kind of stuff.
On a side note, do you think making the speaker name in BIGFONT for Blade of Agony as well might be a good idea in terms of look?
One more question: How do I align the text? The stock diallogue system worked that when the text was without any "\n", it was centered. With "\n" it was aligned to the left. Now all text is aligned to center. Can you replicate this former behaviour? Or tell me how to modify alignement.
Tormentor667 wrote:Brilliant work AFA, I am pretty sure that people will be very happy having a better conversation system on their hands Maybe this would even be interesting to be added to the Realm667 repo... the question is just: Where? Maybe we'd need a new category called "ZScript" for that kind of stuff.
On a side note, do you think making the speaker name in BIGFONT for Blade of Agony as well might be a good idea in terms of look?
Sure, we can add it somehwere in the repo!
I'll port this into BoA once I've tweaked a few things... Namely, adding another bool to restore the option to use the default CONFONT selection cursor, so that everything in-game has the same look.
I also have a set of files that replaces the default blinker cursor on the game menus and the slider bars with graphics that are scaled to the CONFONT components' size (see pic)- problem is, as far as I know, you can't currently replace a menu component/class without using a different name, which necessitates essentially duplicating the entire core MENUDEF - and since the selection cursor is used in both the list and option menu types, it's *all* of the menu entries that have to be re-worked. Plus I haven't been able to figure out how to replace the video settings menu properly; looks like it has a hard-coded exported function.
ramon.dexter wrote:One more question: How do I align the text? The stock diallogue system worked that when the text was without any "\n", it was centered. With "\n" it was aligned to the left. Now all text is aligned to center. Can you replicate this former behaviour? Or tell me how to modify alignement.
Open 'Sample.txt' from the .pk7 - it's under 'Scripts/Conversations'. Scroll to the bottom and find this line: