Skip to content

Commit 53da85f

Browse files
committed
Engine: added DisplayTextPosition to DisplayTextLooks
This amends kDisplayTextStyle_Overchar with a more elaborate combination of settings. Stop using negative x and y in display_main as a telling that the text should be centered. (They are still used in display_speech though, since the script api supports this behavior, whether intentionally or by accident.) Also fixes SayAt being clamped to the screen as if it's regular Say.
1 parent a010ef7 commit 53da85f

File tree

7 files changed

+157
-90
lines changed

7 files changed

+157
-90
lines changed

Engine/ac/character.cpp

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,7 @@ int Character_GetHasExplicitTint(CharacterInfo *ch)
778778
}
779779

780780
void Character_Say(CharacterInfo *chaa, const char *text) {
781-
_DisplaySpeechCore(chaa->index_id, text);
781+
DisplaySpeechCore(chaa->index_id, text);
782782
}
783783

784784
void Character_SayAt(CharacterInfo *chaa, int x, int y, int width, const char *texx) {
@@ -1035,7 +1035,7 @@ void Character_Tint(CharacterInfo *chaa, int red, int green, int blue, int opaci
10351035
}
10361036

10371037
void Character_Think(CharacterInfo *chaa, const char *text) {
1038-
_DisplayThoughtCore(chaa->index_id, text);
1038+
DisplayThoughtCore(chaa->index_id, text);
10391039
}
10401040

10411041
void Character_UnlockView(CharacterInfo *chaa) {
@@ -2493,7 +2493,7 @@ int check_click_on_character(int xx,int yy,int mood) {
24932493
return 0;
24942494
}
24952495

2496-
void _DisplaySpeechCore(int chid, const char *displbuf) {
2496+
void DisplaySpeechCore(int chid, const char *displbuf) {
24972497
if (displbuf[0] == 0) {
24982498
// no text, just update the current character who's speaking
24992499
// this allows the portrait side to be switched with an empty
@@ -2511,30 +2511,25 @@ void _DisplaySpeechCore(int chid, const char *displbuf) {
25112511
DisplaySpeech(displbuf, chid);
25122512
}
25132513

2514-
void _DisplayThoughtCore(int chid, const char *displbuf) {
2514+
void DisplayThoughtCore(int chid, const char *displbuf) {
25152515
// adjust timing of text (so that DisplayThought("%s", str) pauses
25162516
// for the length of the string not 2 frames)
25172517
int len = (int)strlen(displbuf);
25182518
if (len > source_text_length + 3)
25192519
source_text_length = len;
25202520

2521-
int xpp = -1, ypp = -1, width = -1;
2522-
2521+
int width = -1;
25232522
if ((game.options[OPT_SPEECHTYPE] == 0) || (game.chars[chid].thinkview <= 0)) {
25242523
// lucasarts-style, so we want a speech bubble actually above
25252524
// their head (or if they have no think anim in Sierra-style)
25262525
width = data_to_game_coord(play.speech_bubble_width);
2527-
xpp = play.RoomToScreenX(data_to_game_coord(game.chars[chid].x)) - width / 2;
2528-
if (xpp < 0)
2529-
xpp = 0;
2530-
// -1 will automatically put it above the char's head
2531-
ypp = -1;
25322526
}
25332527

2534-
_displayspeech(displbuf, chid, xpp, ypp, width, 1);
2528+
display_speech(displbuf, chid, -1, -1, width, true /*auto-pos*/, true /* is thought */);
25352529
}
25362530

2537-
void _displayspeech(const char*texx, int aschar, int xx, int yy, int widd, int isThought) {
2531+
void display_speech(const char *texx, int aschar, int xx, int yy, int widd, bool auto_position, bool is_thought)
2532+
{
25382533
if (!is_valid_character(aschar))
25392534
quit("!DisplaySpeech: invalid character");
25402535

@@ -2592,29 +2587,32 @@ void _displayspeech(const char*texx, int aschar, int xx, int yy, int widd, int i
25922587
}
25932588

25942589
DisplayTextStyle disp_style = kDisplayTextStyle_Overchar;
2590+
// If the character is in this room, then default to aligning the speech
2591+
// to the character position; but if it's not then center the speech on screen
2592+
DisplayTextPosition disp_pos = auto_position ?
2593+
get_textpos_from_scriptcoords(xx, yy, (speakingChar->room == displayed_room)) :
2594+
kDisplayTextPos_Normal;
25952595
const color_t text_color = speakingChar->talkcolor;
25962596

2597-
Rect ui_view = play.GetUIViewport();
25982597
DisplayTextShrink allow_shrink = kDisplayTextShrink_None;
2598+
bool align_hcenter = false; // whether to align text by centering over position
2599+
2600+
const Rect ui_view = play.GetUIViewport();
25992601
int bwidth = widd;
26002602
if (bwidth < 0)
26012603
bwidth = ui_view.GetWidth()/2 + ui_view.GetWidth()/4;
26022604

26032605
set_our_eip(151);
26042606

26052607
int useview = speakingChar->talkview;
2606-
if (isThought) {
2608+
if (is_thought)
2609+
{
26072610
useview = speakingChar->thinkview;
26082611
// view 0 is not valid for think views
26092612
if (useview == 0)
26102613
useview = -1;
26112614
// speech bubble can shrink to fit
26122615
allow_shrink = kDisplayTextShrink_Left;
2613-
if (speakingChar->room != displayed_room) {
2614-
// not in room, centre it
2615-
xx = -1;
2616-
yy = -1;
2617-
}
26182616
}
26192617

26202618
if (useview >= game.numviews)
@@ -2633,7 +2631,7 @@ void _displayspeech(const char*texx, int aschar, int xx, int yy, int widd, int i
26332631
stop_character_idling(speakingChar);
26342632
}
26352633

2636-
int tdxp = xx,tdyp = yy;
2634+
int tdxp = xx, tdyp = yy;
26372635
int oldview=-1, oldloop = -1;
26382636
int ovr_type = 0;
26392637
text_lips_offset = 0;
@@ -2685,17 +2683,16 @@ void _displayspeech(const char*texx, int aschar, int xx, int yy, int widd, int i
26852683
tdxp = view->RoomToScreen(data_to_game_coord(speakingChar->x), 0).first.X;
26862684
if (tdxp < 2)
26872685
tdxp = 2;
2688-
// tell it to centre it (passing negative x coord further will be treated as a alignment instruction)
2689-
// FIXME: this is unreliable and bug prone, use a separate argument for alignment!
2690-
tdxp = -tdxp;
2686+
// tell it to align it by center
2687+
align_hcenter = auto_position && (xx < 0);
26912688

26922689
if (tdyp < 0)
26932690
{
26942691
int sppic = views[speakingChar->view].loops[speakingChar->loop].frames[0].pic;
26952692
int height = (charextra[aschar].height < 1) ? game.SpriteInfos[sppic].Height : charextra[aschar].height;
26962693
tdyp = view->RoomToScreen(0, data_to_game_coord(charextra[aschar].GetEffectiveY(speakingChar)) - height).first.Y
26972694
- get_fixed_pixel_size(5);
2698-
if (isThought) // if it's a thought, lift it a bit further up
2695+
if (is_thought) // if it's a thought, lift it a bit further up
26992696
tdyp -= get_fixed_pixel_size(10);
27002697
}
27012698
if (tdyp < 5)
@@ -2705,6 +2702,7 @@ void _displayspeech(const char*texx, int aschar, int xx, int yy, int widd, int i
27052702

27062703
if ((useview >= 0) && (game.options[OPT_SPEECHTYPE] > 0)) {
27072704
// Sierra-style close-up portrait
2705+
disp_pos = kDisplayTextPos_Normal;
27082706

27092707
if (play.swap_portrait_lastchar != aschar) {
27102708
// if the portraits are set to Alternate, OR they are
@@ -2900,10 +2898,10 @@ void _displayspeech(const char*texx, int aschar, int xx, int yy, int widd, int i
29002898
facetalkloop = 0;
29012899
facetalkframe = 0;
29022900
facetalkwait = viptr->loops[0].frames[0].speed + GetCharacterSpeechAnimationDelay(speakingChar);
2903-
facetalkrepeat = (isThought) ? 0 : 1;
2901+
facetalkrepeat = (is_thought) ? 0 : 1;
29042902
facetalkBlinkLoop = 0;
29052903
facetalkAllowBlink = 1;
2906-
if ((isThought) && (speakingChar->flags & CHF_NOBLINKANDTHINK))
2904+
if ((is_thought) && (speakingChar->flags & CHF_NOBLINKANDTHINK))
29072905
facetalkAllowBlink = 0;
29082906
facetalkchar = &game.chars[aschar];
29092907
if (facetalkchar->blinktimer < 0)
@@ -2921,7 +2919,7 @@ void _displayspeech(const char*texx, int aschar, int xx, int yy, int widd, int i
29212919
oldview = speakingChar->view;
29222920
oldloop = speakingChar->loop;
29232921

2924-
speakingChar->set_animating(!isThought, // only repeat if speech, not thought
2922+
speakingChar->set_animating(!is_thought, // only repeat if speech, not thought
29252923
true, // always forwards
29262924
GetCharacterSpeechAnimationDelay(speakingChar));
29272925

@@ -2953,33 +2951,32 @@ void _displayspeech(const char*texx, int aschar, int xx, int yy, int widd, int i
29532951
if ((relx < ui_view.GetWidth() / 4) || (relx > ui_view.GetWidth() - (ui_view.GetWidth() / 4)))
29542952
bwidth -= ui_view.GetWidth() / 5;
29552953
}
2956-
/* this causes the text to bob up and down as they talk
2957-
tdxp = OVR_AUTOPLACE;
2958-
tdyp = aschar;*/
2959-
if (!isThought) // set up the lip sync if not thinking
2954+
if (!is_thought) // set up the lip sync if not thinking
29602955
char_speaking_anim = aschar;
2961-
29622956
}
29632957
}
29642958
else
2959+
{
2960+
// If the character is in another room, then center the speech on screen
29652961
allow_shrink = kDisplayTextShrink_Left;
2962+
}
29662963

29672964
// If initial argument was NOT requiring a autoposition,
29682965
// but further calculation set it to be centered, then make it so here
2969-
// (note: this assumes that a valid width is also passed)
2970-
if ((xx >= 0) && (tdxp < 0))
2966+
// (NOTE: this assumes that a valid width is also passed)
2967+
if ((xx >= 0) && align_hcenter)
29712968
tdxp -= widd / 2;
29722969

29732970
// if they used DisplaySpeechAt, then use the supplied width
2974-
if ((widd > 0) && (isThought == 0))
2971+
if ((widd > 0) && (!is_thought))
29752972
allow_shrink = kDisplayTextShrink_None;
29762973

2977-
if (isThought)
2974+
if (is_thought)
29782975
char_thinking = aschar;
29792976

29802977
set_our_eip(155);
29812978
display_main(tdxp, tdyp, bwidth, texx, nullptr, kDisplayText_Speech, 0 /* no overid */,
2982-
DisplayTextLooks(disp_style, isThought, allow_shrink), FONT_SPEECH, text_color, overlayPositionFixed);
2979+
DisplayTextLooks(disp_style, disp_pos, allow_shrink, is_thought), FONT_SPEECH, text_color, overlayPositionFixed);
29832980
set_our_eip(156);
29842981
if ((play.in_conversation > 0) && (game.options[OPT_SPEECHTYPE] == 3))
29852982
closeupface = nullptr;
@@ -3023,8 +3020,9 @@ int get_character_currently_talking() {
30233020
return -1;
30243021
}
30253022

3026-
void DisplaySpeech(const char*texx, int aschar) {
3027-
_displayspeech (texx, aschar, -1, -1, -1, 0);
3023+
void DisplaySpeech(const char *texx, int aschar)
3024+
{
3025+
display_speech(texx, aschar, -1, -1, -1, true /*auto-pos*/, false /* not thought */);
30283026
}
30293027

30303028
// Calculate which frame of the loop to use for this character of

Engine/ac/character.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,12 @@
1111
// https://opensource.org/license/artistic-2-0/
1212
//
1313
//=============================================================================
14-
//
15-
//
16-
//
17-
//=============================================================================
1814
#ifndef __AGS_EE_AC__CHARACTER_H
1915
#define __AGS_EE_AC__CHARACTER_H
2016

2117
#include "ac/characterinfo.h"
2218
#include "ac/characterextras.h"
19+
#include "ac/display.h"
2320
#include "ac/dynobj/scriptobject.h"
2421
#include "ac/dynobj/scriptinvitem.h"
2522
#include "ac/dynobj/scriptoverlay.h"
@@ -212,9 +209,13 @@ int my_getpixel(Common::Bitmap *blk, int x, int y);
212209
// X and Y co-ordinates must be in 320x200 format
213210
int check_click_on_character(int xx,int yy,int mood);
214211
int is_pos_on_character(int xx,int yy);
215-
void _DisplaySpeechCore(int chid, const char *displbuf);
216-
void _DisplayThoughtCore(int chid, const char *displbuf);
217-
void _displayspeech(const char*texx, int aschar, int xx, int yy, int widd, int isThought);
212+
void DisplaySpeechCore(int chid, const char *displbuf);
213+
void DisplayThoughtCore(int chid, const char *displbuf);
214+
// Displays character speech or thought message.
215+
// When auto-position flag is on, passing negative coordinates will request
216+
// auto-position on the respective axis. The nature of auto-pos will depend
217+
// on a speech style. E.g. LA speech aligns above character's head.
218+
void display_speech(const char *texx, int aschar, int xx, int yy, int widd, bool auto_position, bool is_thought);
218219
int get_character_currently_talking();
219220
void DisplaySpeech(const char*texx, int aschar);
220221
int update_lip_sync(int talkview, int talkloop, int *talkframeptr);

Engine/ac/display.cpp

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,22 @@ class DisplayMessageState : public GameState
137137
};
138138

139139

140+
DisplayTextPosition get_textpos_from_scriptcoords(int x, int y, bool for_speech)
141+
{
142+
int text_pos = kDisplayTextPos_Normal;
143+
if (for_speech)
144+
{
145+
if (x < 0) text_pos |= kDisplayTextPos_OvercharX;
146+
if (y < 0) text_pos |= kDisplayTextPos_OvercharY;
147+
}
148+
else
149+
{
150+
if (x < 0) text_pos |= kDisplayTextPos_ScreenCenterX;
151+
if (y < 0) text_pos |= kDisplayTextPos_ScreenCenterY;
152+
}
153+
return (DisplayTextPosition)text_pos;
154+
}
140155

141-
// Generates a textual image and returns a disposable bitmap
142-
// FIXME: for historical reasons this function also contains position adjustment;
143-
// but this should not be done here at all.
144-
// FIXME: xx is allowed to be passed as OVR_AUTOPLACE, which has special meaning,
145-
// but that's a confusing use of this argument.
146156
Bitmap *create_textual_image(const char *text, const DisplayTextLooks &look, color_t text_color,
147157
int &xx, int &yy, int &adjustedXX, int &adjustedYY, int wii, int usingfont,
148158
bool &alphaChannel, const TopBarSettings *topbar)
@@ -178,25 +188,37 @@ Bitmap *create_textual_image(const char *text, const DisplayTextLooks &look, col
178188
get_font_linespacing(usingfont),
179189
get_text_lines_surf_height(usingfont, Lines.Count()));
180190

181-
if (topbar) {
191+
if (topbar)
192+
{
182193
// ensure that the window is wide enough to display any top bar text
183194
int topBarWid = get_text_width_outlined(topbar->Text.GetCStr(), topbar->Font);
184195
topBarWid += data_to_game_coord(play.top_bar_borderwidth + 2) * 2;
185196
if (longestline < topBarWid)
186197
longestline = topBarWid;
187198
}
188199

189-
const bool auto_align_pos = xx < -1; // sic, it was suggesting x < -1
190200
const Rect &ui_view = play.GetUIViewport();
191-
if (xx == OVR_AUTOPLACE);
201+
if (xx == OVR_AUTOPLACE) {} // FIXME: don't use OVR_AUTOPLACE here
192202
// centre text in middle of screen
193-
else if (yy<0) yy = ui_view.GetHeight() / 2 - disp.FullTextHeight / 2 - padding;
194-
// speech, so it wants to be above the character's head
195-
else if (look.Style == kDisplayTextStyle_Overchar) {
196-
// If ordered to auto align, then first make sure that the position is on screen
197-
if (auto_align_pos) {
198-
yy = Math::Clamp(yy, disp.FullTextHeight + screen_padding, ui_view.GetHeight() - screen_padding);
199-
}
203+
else if ((look.Position & kDisplayTextPos_ScreenCenterY) != 0)
204+
{
205+
yy = ui_view.GetHeight() / 2 - disp.FullTextHeight / 2 - padding;
206+
}
207+
// LA-style speech, so it wants to be above the character's head
208+
else if ((look.Position & kDisplayTextPos_OvercharY) != 0)
209+
{
210+
// Clamp text position to screen bounds, and align by the text's bottom
211+
yy = Math::Clamp(yy, disp.FullTextHeight + screen_padding, ui_view.GetHeight() - screen_padding);
212+
yy -= disp.FullTextHeight;
213+
yy = adjust_y_for_guis(yy);
214+
}
215+
// NOTE: this is possibly an accidental mistake, but historically
216+
// this Y pos fixup is also applied for SayAt, which results in
217+
// text's origin being a left-bottom rather than left-top.
218+
// Maybe this could be fixed in some future versions...
219+
else if (look.Style == kDisplayTextStyle_Overchar)
220+
{
221+
yy = std::max(yy, disp.FullTextHeight + screen_padding);
200222
yy -= disp.FullTextHeight;
201223
yy = adjust_y_for_guis(yy);
202224
}
@@ -213,15 +235,18 @@ Bitmap *create_textual_image(const char *text, const DisplayTextLooks &look, col
213235
xx += (oldWid - wii);
214236
}
215237

216-
// If ordered to center around the x pos, then do so, and fixup
217-
if (auto_align_pos) {
218-
xx = (-xx) - wii / 2;
238+
if (xx == OVR_AUTOPLACE) {} // FIXME: don't use OVR_AUTOPLACE here
239+
else if ((look.Position & kDisplayTextPos_ScreenCenterX) != 0)
240+
{
241+
xx = ui_view.GetWidth() / 2 - wii / 2;
242+
}
243+
// If ordered to center around the x pos, then do so, and clamp to the screen bounds
244+
else if ((look.Position & kDisplayTextPos_OvercharX) != 0)
245+
{
246+
xx -= wii / 2;
219247
xx = Math::Clamp(xx, screen_padding, ui_view.GetWidth() - screen_padding - wii);
220248
xx = adjust_x_for_guis(xx, yy);
221249
}
222-
// FIXME: this is unreliable, will execute only of xx == -1,
223-
// but what if it's +1 inverted for centering?
224-
else if (xx<0) xx = ui_view.GetWidth() / 2 - wii / 2;
225250

226251
const int extraHeight = paddingDoubledScaled;
227252
const int bmp_width = std::max(2, wii);
@@ -371,9 +396,6 @@ bool display_check_user_input(int skip)
371396
return state_handled;
372397
}
373398

374-
// Pass yy = -1 to find Y co-ord automatically
375-
// allowShrink = 0 for none, 1 for leftwards, 2 for rightwards
376-
// pass blocking=2 to create permanent overlay
377399
ScreenOverlay *display_main(int xx, int yy, int wii, const char *text,
378400
const TopBarSettings *topbar, DisplayTextType disp_type, int over_id,
379401
const DisplayTextLooks &look, int usingfont, color_t text_color,
@@ -405,7 +427,8 @@ ScreenOverlay *display_main(int xx, int yy, int wii, const char *text,
405427
disp_type = kDisplayText_Speech;
406428
}
407429

408-
if ((look.Style == kDisplayTextStyle_Overchar) && (disp_type < kDisplayText_NormalOverlay))
430+
if ((look.Style == kDisplayTextStyle_PlainText || look.Style == kDisplayTextStyle_Overchar)
431+
&& (disp_type < kDisplayText_NormalOverlay))
409432
{
410433
// update the all_buttons_disabled variable in advance
411434
// of the adjust_x/y_for_guis calls

0 commit comments

Comments
 (0)