316 lines
8.5 KiB
C++
316 lines
8.5 KiB
C++
/*
|
|
* Copyright (c) 2016-2022 Vera Visions LLC.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
/* for effect 2 */
|
|
static int
|
|
GameText_CharCount(float fadein, float timer, string msg)
|
|
{
|
|
float len = (timer / fadein);
|
|
|
|
if (!fadein || len > strlen(msg))
|
|
return strlen(msg);
|
|
else
|
|
return len;
|
|
}
|
|
|
|
/* the engine its drawstring doesn't like newlines that much */
|
|
static void
|
|
GameText_DrawString(vector pos, string msg, vector col, float alpha)
|
|
{
|
|
vector rpos = [0.0f, 0.0f, 0.0f];
|
|
int c = tokenizebyseparator(msg, "\n");
|
|
|
|
for (int i = 0; i < c; i++) {
|
|
float strwidth = Font_StringWidth(argv(i), TRUE, FONT_20);
|
|
|
|
if (pos[0] == -1) {
|
|
rpos[0] = g_hudmins[0] + (g_hudres[0] / 2) - (strwidth/2);
|
|
} else {
|
|
rpos[0] = g_hudmins[0] + g_hudres[0] * pos[0];
|
|
|
|
if (pos[0] >= 0.5) {
|
|
rpos[0] -= strwidth;
|
|
}
|
|
}
|
|
|
|
if (pos[1] == -1) {
|
|
rpos[1] = g_hudmins[1] + (g_hudres[1] / 2) - 6;
|
|
} else {
|
|
rpos[1] = g_hudmins[1] + ((g_hudres[1] - 12) * pos[1]);
|
|
}
|
|
rpos[1] += Font_GetHeight(FONT_20) * i;
|
|
rpos[1] -= (Font_GetHeight(FONT_20) * c) / 2;
|
|
|
|
Font_DrawText_RGBA(rpos, argv(i), col, alpha, FONT_20);
|
|
}
|
|
}
|
|
|
|
static void
|
|
GameText_DrawMessage(gametext_t *txt, float timer, int highlight)
|
|
{
|
|
float a = 0.0f;
|
|
vector rpos = [0.0f, 0.0f, 0.0f];
|
|
float mtime;
|
|
float btime;
|
|
string finalstr;
|
|
|
|
/* typing effect */
|
|
if (txt->m_iEffect == 2) {
|
|
/* scan out */
|
|
finalstr = substring(txt->m_strMessage, 0,
|
|
GameText_CharCount(txt->m_flFadeIn, timer,
|
|
txt->m_strMessage));
|
|
} else {
|
|
finalstr = txt->m_strMessage;
|
|
}
|
|
|
|
timer = max(0, timer);
|
|
|
|
if (highlight) {
|
|
btime = txt->m_flFadeIn * \
|
|
strlen(txt->m_strMessage);
|
|
mtime = btime + txt->m_flFadeOut;
|
|
} else {
|
|
mtime = txt->m_flFadeIn + \
|
|
txt->m_flHoldTime + \
|
|
txt->m_flFadeOut;
|
|
btime = txt->m_flFadeIn + \
|
|
txt->m_flHoldTime;
|
|
}
|
|
|
|
if (timer > mtime) {
|
|
return;
|
|
}
|
|
|
|
if (timer < txt->m_flFadeIn) {
|
|
a = (timer / txt->m_flFadeIn);
|
|
} else if (timer < btime) {
|
|
a = 1.0f;
|
|
} else if (timer < mtime) {
|
|
if (txt->m_flFadeOut) {
|
|
a = 1 - (timer - btime) / txt->m_flFadeOut;
|
|
}
|
|
}
|
|
|
|
rpos[0] = txt->m_flPosX;
|
|
rpos[1] = txt->m_flPosY;
|
|
|
|
if (highlight) {
|
|
GameText_DrawString(rpos, finalstr, txt->m_vecColor2, a);
|
|
} else {
|
|
GameText_DrawString(rpos, finalstr, txt->m_vecColor1, a);
|
|
}
|
|
}
|
|
|
|
static void
|
|
GameText_Copy(gametext_t *src, gametext_t *dest)
|
|
{
|
|
dest->m_strMessage = src->m_strMessage;
|
|
dest->m_flTime = src->m_flTime;
|
|
dest->m_flPosX = src->m_flPosX;
|
|
dest->m_iEffect = src->m_iEffect;
|
|
dest->m_vecColor2 = src->m_vecColor2;
|
|
dest->m_flFadeIn = src->m_flFadeIn;
|
|
dest->m_flFadeOut = src->m_flFadeOut;
|
|
dest->m_flHoldTime = src->m_flHoldTime;
|
|
dest->m_flFXTime = src->m_flFXTime;
|
|
dest->m_vecColor1 = src->m_vecColor1;
|
|
dest->m_vecColor2 = src->m_vecColor2;
|
|
}
|
|
|
|
static void
|
|
GameText_QueueNext(void)
|
|
{
|
|
for (int i = 0; i < (g_textqueue_count-1); i++) {
|
|
GameText_Copy(&g_textqueue[i+1], &g_textqueue[i]);
|
|
}
|
|
g_textqueue_next--;
|
|
g_textqueue_count--;
|
|
}
|
|
|
|
void
|
|
GameText_Draw(void)
|
|
{
|
|
vector debugPos = [16,16];
|
|
|
|
if (cvar("r_showTexts") > 0)
|
|
Font_DrawText(debugPos, "Text Debug Information", FONT_CON);
|
|
|
|
debugPos[1] += 20;
|
|
|
|
for (int i = 0i; i < 6; i++) {
|
|
/* we'll draw the highlight separately */
|
|
GameText_DrawMessage(&g_textchannels[i], g_textchannels[i].m_flTime - g_textchannels[i].m_flFXTime, 0); /* first pass */
|
|
|
|
/* effect 0 has no highlight */
|
|
if (g_textchannels[i].m_iEffect != 0)
|
|
GameText_DrawMessage(&g_textchannels[i], g_textchannels[i].m_flTime, 1); /* second pass */
|
|
|
|
g_textchannels[i].m_flTime += clframetime;
|
|
|
|
if (cvar("r_showTexts") <= 0)
|
|
continue;
|
|
|
|
Font_DrawText(debugPos, sprintf("Chan %i: E %i T: %f/%f", i, g_textchannels[i].m_iEffect, g_textchannels[i].m_flTime, g_textchannels[i].m_flHoldTime), FONT_CON);
|
|
debugPos[1] += 20;
|
|
}
|
|
|
|
/* process the channel 0 queue */
|
|
if (g_textqueue_count <= 0) {
|
|
return;
|
|
}
|
|
|
|
/* if the message is empty, move the msgs down by 1 */
|
|
if (g_textqueue[0].m_strMessage == __NULL__) {
|
|
GameText_QueueNext();
|
|
}
|
|
|
|
GameText_DrawMessage(&g_textqueue[0], g_textqueue[0].m_flTime - g_textqueue[0].m_flFXTime, 0); /* first pass */
|
|
|
|
if (g_textqueue[0].m_iEffect != 0)
|
|
GameText_DrawMessage(&g_textqueue[0], g_textqueue[0].m_flTime, 1); /* second pass */
|
|
|
|
g_textqueue[0].m_flTime += clframetime;
|
|
|
|
float maxTime = g_textqueue[0].m_flFadeIn + g_textqueue[0].m_flFadeOut + g_textqueue[0].m_flHoldTime + g_textqueue[0].m_flFXTime;
|
|
|
|
if (g_textqueue[0].m_flTime >= maxTime)
|
|
g_textqueue[0].m_strMessage = __NULL__;
|
|
|
|
}
|
|
|
|
void
|
|
GameText_ParseString(void)
|
|
{
|
|
int chan = readbyte();
|
|
|
|
/* last channel is reserved for text menus */
|
|
if (!(chan >= 0 && chan <= 4)) {
|
|
return;
|
|
}
|
|
|
|
g_textchannels[chan].m_strMessage = Titles_ParseFunString(readstring());
|
|
g_textchannels[chan].m_flPosX = readfloat();
|
|
g_textchannels[chan].m_flPosY = readfloat();
|
|
g_textchannels[chan].m_iEffect = readbyte();
|
|
g_textchannels[chan].m_vecColor1[0] = readbyte() / 255;
|
|
g_textchannels[chan].m_vecColor1[1] = readbyte() / 255;
|
|
g_textchannels[chan].m_vecColor1[2] = readbyte() / 255;
|
|
g_textchannels[chan].m_vecColor2[0] = readbyte() / 255;
|
|
g_textchannels[chan].m_vecColor2[1] = readbyte() / 255;
|
|
g_textchannels[chan].m_vecColor2[2] = readbyte() / 255;
|
|
g_textchannels[chan].m_flFadeIn = readfloat();
|
|
g_textchannels[chan].m_flFadeOut = readfloat();
|
|
g_textchannels[chan].m_flHoldTime = readfloat();
|
|
g_textchannels[chan].m_flFXTime = readfloat();
|
|
g_textchannels[chan].m_flTime = 0.0f;
|
|
}
|
|
|
|
void
|
|
GameText_Parse(void)
|
|
{
|
|
int chan = readbyte();
|
|
|
|
/* last channel is reserved for text menus */
|
|
if (!(chan >= 0 && chan <= 4)) {
|
|
return;
|
|
}
|
|
|
|
g_textchannels[chan].m_strMessage = Titles_ParseFunString(readstring());
|
|
g_textchannels[chan].m_flPosX = readfloat();
|
|
g_textchannels[chan].m_flPosY = readfloat();
|
|
g_textchannels[chan].m_iEffect = readbyte();
|
|
g_textchannels[chan].m_vecColor1[0] = readbyte() / 255;
|
|
g_textchannels[chan].m_vecColor1[1] = readbyte() / 255;
|
|
g_textchannels[chan].m_vecColor1[2] = readbyte() / 255;
|
|
g_textchannels[chan].m_vecColor2[0] = readbyte() / 255;
|
|
g_textchannels[chan].m_vecColor2[1] = readbyte() / 255;
|
|
g_textchannels[chan].m_vecColor2[2] = readbyte() / 255;
|
|
g_textchannels[chan].m_flFadeIn = readfloat();
|
|
g_textchannels[chan].m_flFadeOut = readfloat();
|
|
g_textchannels[chan].m_flHoldTime = readfloat();
|
|
g_textchannels[chan].m_flFXTime = readfloat();
|
|
g_textchannels[chan].m_flTime = 0.0f;
|
|
}
|
|
|
|
void
|
|
GameMessage_Setup(string message, int channel)
|
|
{
|
|
gametext_t *next;
|
|
int findid = -1;
|
|
|
|
for (int i = 0; i < g_titles_count; i++) {
|
|
if (g_titles[i].m_strName == message) {
|
|
findid = i;
|
|
}
|
|
}
|
|
|
|
/* channel 0 is a rotating queue */
|
|
if (channel == 0) {
|
|
/* clear the oldest message if needed */
|
|
if (g_textqueue_next + 1 >= TEXTQUEUE_MAX)
|
|
GameText_QueueNext();
|
|
|
|
channel = g_textqueue_next++;
|
|
next = &g_textqueue[channel];
|
|
g_textqueue_count++;
|
|
|
|
} else {
|
|
next = &g_textchannels[channel];
|
|
}
|
|
|
|
if (findid < 0) {
|
|
next->m_strMessage = Titles_ParseFunString(message);
|
|
next->m_flTime = 0.0f;
|
|
next->m_flPosX = -1;
|
|
next->m_flPosY = 0.75f;
|
|
next->m_flFadeIn = 0.5f;
|
|
next->m_flFadeOut = 0.5f;
|
|
next->m_flHoldTime = 2.0f;
|
|
next->m_vecColor1 = [1,1,1];
|
|
next->m_vecColor2 = [1,1,1];
|
|
} else {
|
|
next->m_strMessage = g_titles[findid].m_strMessage;
|
|
next->m_flTime = 0.0f;
|
|
next->m_flPosX = g_titles[findid].m_flPosX;
|
|
next->m_flPosY = g_titles[findid].m_flPosY;
|
|
next->m_flFadeIn = g_titles[findid].m_flFadeIn;
|
|
next->m_flFadeOut = g_titles[findid].m_flFadeOut;
|
|
next->m_flHoldTime = g_titles[findid].m_flHoldTime;
|
|
next->m_vecColor1 = g_titles[findid].m_vecColor1;
|
|
next->m_vecColor2 = g_titles[findid].m_vecColor2;
|
|
next->m_iEffect = g_titles[findid].m_iEffect;
|
|
}
|
|
}
|
|
|
|
void
|
|
GameMessage_Parse(void)
|
|
{
|
|
string strSound;
|
|
float flVolume;
|
|
int iAttenuation;
|
|
string findme;
|
|
|
|
findme = strtoupper(readstring());
|
|
GameMessage_Setup(findme, 0);
|
|
|
|
strSound = readstring();
|
|
flVolume = readfloat();
|
|
iAttenuation = readbyte();
|
|
|
|
if (strSound)
|
|
sound(self, CHAN_ITEM, strSound, flVolume, iAttenuation);
|
|
}
|