mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2025-01-31 04:30:39 +00:00
d16b46e3cf
Overhauled child entity movement in default Lazarus DLL. Added bbox versions of various triggers to default Lazarus DLL. Added level.maptype field to default Lazarus DLL. Added entity class IDs to default Lazarus DLL. Incremented savegame version for default Lazarus DLL.
770 lines
18 KiB
C
770 lines
18 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1997-2001 Id Software, Inc.
|
|
Copyright (C) 2000-2002 Mr. Hyde and Mad Dog
|
|
|
|
This file is part of Lazarus Quake 2 Mod source code.
|
|
|
|
Lazarus Quake 2 Mod source code is free software; you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
Lazarus Quake 2 Mod source code is distributed in the hope that it will be
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Lazarus Quake 2 Mod source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "g_local.h"
|
|
#include "pak.h"
|
|
|
|
#define MAX_LINES 24
|
|
#define MAX_LINE_LENGTH 35
|
|
|
|
text_t text[MAX_LINES];
|
|
|
|
void Text_Open(edict_t *ent)
|
|
{
|
|
if (!ent->client)
|
|
return;
|
|
ent->client->showscores = true;
|
|
ent->client->inmenu = true;
|
|
ent->client->textdisplay->last_update = 0;
|
|
Text_Update(ent);
|
|
}
|
|
|
|
void Text_Close(edict_t *ent)
|
|
{
|
|
if (!ent->client) return;
|
|
if (!ent->client->textdisplay) return;
|
|
if (ent->client->textdisplay->buffer)
|
|
{
|
|
gi.TagFree(ent->client->textdisplay->buffer);
|
|
ent->client->textdisplay->buffer = NULL;
|
|
}
|
|
gi.TagFree(ent->client->textdisplay);
|
|
ent->client->textdisplay = NULL;
|
|
ent->client->showscores = false;
|
|
}
|
|
|
|
void Text_BuildDisplay(texthnd_t *hnd)
|
|
{
|
|
int i, imax, n;
|
|
char *p1, *p2, *p3;
|
|
|
|
for (i=0; i<hnd->page_length+2; i++)
|
|
text[i].text = NULL;
|
|
|
|
if (!(hnd->flags & 2))
|
|
{
|
|
text[hnd->page_length+1].text = "Esc to quit";
|
|
if (hnd->nlines > hnd->page_length)
|
|
text[hnd->page_length].text = "Use [ and ] to scroll";
|
|
}
|
|
|
|
p1 = hnd->buffer+hnd->start_char;
|
|
p3 = hnd->buffer+hnd->size-1;
|
|
if (hnd->curline > 0)
|
|
{
|
|
// Scan for hnd->curline'th 0 byte, point to following character
|
|
n = hnd->curline;
|
|
while (p1 < p3 && n)
|
|
{
|
|
if (*p1==0) n--;
|
|
p1++;
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
p2 = p1;
|
|
text[i].text = p2;
|
|
if (hnd->nlines > hnd->page_length)
|
|
imax = hnd->page_length-2;
|
|
else
|
|
imax = hnd->page_length-1;
|
|
while (p2 <= p3 && i < imax)
|
|
{
|
|
if (*p2 == 0 && p2 < p3)
|
|
{
|
|
i++;
|
|
p2++;
|
|
text[i].text = p2;
|
|
}
|
|
else
|
|
p2++;
|
|
}
|
|
}
|
|
|
|
void Text_Update(edict_t *ent)
|
|
{
|
|
int align;
|
|
int i;
|
|
int x0, y0;
|
|
text_t *p;
|
|
int x, xlast;
|
|
char *t, *tnext;
|
|
qboolean alt = false;
|
|
char string[2048];
|
|
texthnd_t *hnd;
|
|
|
|
|
|
if (!ent->client->textdisplay) {
|
|
gi.dprintf("warning: ent has no text display\n");
|
|
return;
|
|
}
|
|
|
|
hnd = ent->client->textdisplay;
|
|
if (hnd->last_update + 2*FRAMETIME > level.time) return;
|
|
hnd->last_update = level.time;
|
|
|
|
|
|
x0 = (35 - hnd->page_width)*4;
|
|
y0 = (22 - hnd->page_length)*4;
|
|
|
|
if (!(hnd->flags & 2))
|
|
{
|
|
Com_sprintf (string, sizeof(string), "xv %d yv %d picn %s ",
|
|
x0, y0, hnd->background_image);
|
|
}
|
|
else // Knightmare- we NEED to have a placeholder image here
|
|
Com_sprintf (string, sizeof(string), "xv %d yv %d picn blank ", x0, y0);
|
|
xlast = 9999;
|
|
|
|
for (i = 0, p = hnd->lines; i < hnd->page_length+2; i++, p++)
|
|
{
|
|
if (!p->text || !*(p->text)) // crashes here on load
|
|
continue; // blank line
|
|
t = p->text;
|
|
if (*t == '*') {
|
|
alt = true;
|
|
t++;
|
|
}
|
|
align = TEXT_LEFT;
|
|
if (*t == '\\')
|
|
{
|
|
tnext = t;
|
|
tnext++;
|
|
if (*tnext == 'c')
|
|
{
|
|
align = TEXT_CENTER;
|
|
t++;
|
|
t++;
|
|
}
|
|
if (*tnext == 'r')
|
|
{
|
|
align = TEXT_RIGHT;
|
|
t++;
|
|
t++;
|
|
}
|
|
}
|
|
if (strlen(t))
|
|
{
|
|
// sprintf(string + strlen(string), "yv %d ", y0 + 24 + i * 8);
|
|
Com_sprintf (string + strlen(string), sizeof(string)-strlen(string), "yv %d ", y0 + 24 + i * 8);
|
|
if (align == TEXT_CENTER)
|
|
x = x0 + 20 + (hnd->page_width-1-(int)strlen(t))*4;
|
|
else if (align == TEXT_RIGHT)
|
|
x = x0 + 20 + (hnd->page_width-1-(int)strlen(t))*8;
|
|
else
|
|
x = x0 + 20;
|
|
if (x != xlast)
|
|
{
|
|
// sprintf(string + strlen(string), "xv %d ",x);
|
|
Com_sprintf (string + strlen(string), sizeof(string)-strlen(string), "xv %d ",x);
|
|
xlast = x;
|
|
}
|
|
if (alt) {
|
|
// sprintf(string + strlen(string), "string2 \"%s\" ", t);
|
|
Com_sprintf (string + strlen(string), sizeof(string)-strlen(string), "string2 \"%s\" ", t);
|
|
}
|
|
else {
|
|
// sprintf(string + strlen(string), "string \"%s\" ", t);
|
|
Com_sprintf (string + strlen(string), sizeof(string)-strlen(string), "string \"%s\" ", t);
|
|
}
|
|
}
|
|
alt = false;
|
|
}
|
|
// if (strlen(string) > 1000)
|
|
// gi.dprintf("WARNING: formatted string length (%d) > 1000\n",strlen(string));
|
|
|
|
gi.WriteByte (svc_layout);
|
|
gi.WriteString (string);
|
|
gi.unicast (ent, true);
|
|
}
|
|
|
|
void Text_Next(edict_t *ent)
|
|
{
|
|
int current;
|
|
int displayed_lines;
|
|
texthnd_t *hnd;
|
|
|
|
if (!ent->client->textdisplay) {
|
|
gi.dprintf("warning: ent has no text display\n");
|
|
return;
|
|
}
|
|
|
|
hnd = ent->client->textdisplay;
|
|
|
|
displayed_lines = hnd->page_length;
|
|
if (hnd->nlines > hnd->page_length) displayed_lines--;
|
|
if (hnd->curline+displayed_lines+1 < hnd->nlines)
|
|
{
|
|
current = hnd->curline;
|
|
// hnd->curline = min(hnd->curline+MAX_LINES/2,hnd->nlines-displayed_lines-1);
|
|
hnd->curline = hnd->curline+hnd->page_length-1;
|
|
if (hnd->curline > current)
|
|
{
|
|
Text_BuildDisplay(hnd);
|
|
Text_Update(ent);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Text_Prev(edict_t *ent)
|
|
{
|
|
texthnd_t *hnd;
|
|
|
|
if (!ent->client->textdisplay) {
|
|
gi.dprintf("warning: ent has no text display\n");
|
|
return;
|
|
}
|
|
|
|
hnd = ent->client->textdisplay;
|
|
|
|
if (hnd->curline > 0)
|
|
{
|
|
// hnd->curline = max(0, hnd->curline-MAX_LINES/2);
|
|
hnd->curline = max(0, hnd->curline-hnd->page_length+1);
|
|
Text_BuildDisplay(hnd);
|
|
Text_Update(ent);
|
|
}
|
|
}
|
|
|
|
|
|
void Do_Text_Display(edict_t *activator, int flags, char *message)
|
|
{
|
|
int /*i,*/ L;
|
|
byte *p1, *p2, *p3; // was char *
|
|
char sound[64];
|
|
texthnd_t *hnd;
|
|
byte *temp_buffer;
|
|
int line_length;
|
|
int new_line_length;
|
|
qboolean alt, centered, right_justified;
|
|
qboolean linebreak;
|
|
qboolean do_linebreaks;
|
|
|
|
hnd = gi.TagMalloc(sizeof(*hnd), TAG_LEVEL);
|
|
// If a file, open and read it
|
|
if (flags & 1)
|
|
{
|
|
#ifdef KMQUAKE2_ENGINE_MOD // use new engine file loading function instead
|
|
char textname[128];
|
|
int textsize;
|
|
byte *readbuffer;
|
|
|
|
// sprintf(textname,"maps/%s", message);
|
|
Com_sprintf(textname, sizeof(textname), "maps/%s", message);
|
|
|
|
textsize = gi.LoadFile(textname, (void **)&readbuffer);
|
|
if (textsize < 2) // file not found
|
|
{
|
|
gi.dprintf("File not found: %s\n",textname);
|
|
return;
|
|
}
|
|
hnd->allocated = textsize + 128; // add some slop for additional control characters
|
|
hnd->buffer = gi.TagMalloc(hnd->allocated, TAG_LEVEL);
|
|
if (!hnd->buffer)
|
|
{
|
|
gi.dprintf("Memory allocation failure on target_text\n");
|
|
Text_Close(activator);
|
|
return;
|
|
}
|
|
memset(hnd->buffer,0,hnd->allocated);
|
|
memcpy(hnd->buffer, readbuffer, textsize);
|
|
hnd->buffer[textsize] = 0;
|
|
gi.FreeFile(readbuffer);
|
|
#else
|
|
cvar_t *basedir, *gamedir;
|
|
char filename[256];
|
|
char pakfile[256];
|
|
char textname[128];
|
|
int i, k, num, numitems;
|
|
qboolean in_pak;
|
|
FILE *f;
|
|
pak_header_t pakheader;
|
|
pak_item_t pakitem;
|
|
|
|
basedir = gi.cvar("basedir", "", 0);
|
|
gamedir = gi.cvar("gamedir", "", 0);
|
|
/*
|
|
Q_strncpyz(filename, basedir->string, sizeof(filename));
|
|
if (strlen(gamedir->string))
|
|
{
|
|
Q_strncatz(filename, "\\", sizeof(filename));
|
|
Q_strncatz(filename, gamedir->string, sizeof(filename));
|
|
}
|
|
*/
|
|
if (strlen(gamedir->string))
|
|
Com_sprintf(filename, sizeof(filename), "%s\\%s", basedir->string, gamedir->string);
|
|
else
|
|
Com_sprintf(filename, sizeof(filename), "%s\\baseq2", basedir->string);
|
|
|
|
// First check for existence of text file in pak0.pak -> pak9.pak
|
|
in_pak = false;
|
|
for (i=0; i<=9 && !in_pak; i++)
|
|
{
|
|
Com_sprintf(pakfile, sizeof(pakfile), "%s\\pak%d.pak", filename, i);
|
|
if (NULL != (f = fopen(pakfile, "rb")))
|
|
{
|
|
num = (int)fread(&pakheader,1,sizeof(pak_header_t),f);
|
|
if (num >= sizeof(pak_header_t))
|
|
{
|
|
if ( pakheader.id[0] == 'P' &&
|
|
pakheader.id[1] == 'A' &&
|
|
pakheader.id[2] == 'C' &&
|
|
pakheader.id[3] == 'K' )
|
|
{
|
|
numitems = pakheader.dsize/sizeof(pak_item_t);
|
|
// sprintf(textname,"maps/%s",message);
|
|
Com_sprintf(textname, sizeof(textname), "maps/%s", message);
|
|
fseek(f, pakheader.dstart, SEEK_SET);
|
|
for (k=0; k<numitems && !in_pak; k++)
|
|
{
|
|
fread(&pakitem, 1, sizeof(pak_item_t), f);
|
|
if (!Q_stricmp(pakitem.name,textname))
|
|
{
|
|
in_pak = true;
|
|
fseek(f, pakitem.start, SEEK_SET);
|
|
hnd->allocated = pakitem.size + 128; // add some slop for additional control characters
|
|
hnd->buffer = gi.TagMalloc(hnd->allocated, TAG_LEVEL);
|
|
if (!hnd->buffer)
|
|
{
|
|
fclose(f);
|
|
gi.dprintf("Memory allocation failure on target_text\n");
|
|
Text_Close(activator);
|
|
return;
|
|
}
|
|
memset(hnd->buffer, 0, hnd->allocated);
|
|
fread(hnd->buffer, 1, pakitem.size, f);
|
|
hnd->buffer[pakitem.size] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fclose(f);
|
|
}
|
|
}
|
|
if (!in_pak)
|
|
{
|
|
// strncat(filename, "\\maps\\");
|
|
// strncat(filename, message);
|
|
Q_strncatz(filename, "\\maps\\", sizeof(filename));
|
|
Q_strncatz(filename, message, sizeof(filename));
|
|
f = fopen(filename,"rb");
|
|
if (!f)
|
|
{
|
|
gi.dprintf("File not found:%s\n",filename);
|
|
return;
|
|
}
|
|
fseek(f,0,SEEK_END);
|
|
L = ftell (f);
|
|
fseek(f,0,SEEK_SET);
|
|
hnd->allocated = L+128;
|
|
hnd->buffer = gi.TagMalloc(hnd->allocated, TAG_LEVEL);
|
|
if (!hnd->buffer)
|
|
{
|
|
gi.dprintf("Memory allocation failure on target_text\n");
|
|
Text_Close(activator);
|
|
return;
|
|
}
|
|
memset(hnd->buffer,0,hnd->allocated);
|
|
fread(hnd->buffer,1,L,f);
|
|
fclose(f);
|
|
}
|
|
#endif // KMQUAKE2_ENGINE_MOD
|
|
|
|
if (!hnd->buffer)
|
|
{
|
|
gi.dprintf("Umm... how'd you get here?\n");
|
|
Text_Close(activator);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
L = (int)strlen(message);
|
|
hnd->allocated = L+128;
|
|
hnd->buffer = gi.TagMalloc(hnd->allocated, TAG_LEVEL);
|
|
if (!hnd->buffer)
|
|
{
|
|
gi.dprintf("Memory allocation failure\n");
|
|
Text_Close(activator);
|
|
return;
|
|
}
|
|
memset(hnd->buffer,0,hnd->allocated);
|
|
memcpy(hnd->buffer,message,L);
|
|
}
|
|
|
|
hnd->size = (int)strlen(hnd->buffer) + 1;
|
|
|
|
// Default page length:
|
|
hnd->page_length = MAX_LINES-2;
|
|
hnd->page_width = MAX_LINE_LENGTH;
|
|
// strncpy(hnd->background_image,"textdisplay");
|
|
Q_strncpyz(hnd->background_image,"textdisplay", sizeof(hnd->background_image));
|
|
hnd->start_char = 0;
|
|
do_linebreaks = true;
|
|
|
|
// If 1st line starts with $, read page length, width, and image name
|
|
p1 = hnd->buffer;
|
|
if (*p1 == '$')
|
|
{
|
|
p3 = p1;
|
|
while ((p3 < hnd->buffer+hnd->size) && (*p3 != 13))
|
|
p3++;
|
|
|
|
p2 = strstr(p1,"L=");
|
|
if (p2 && (p2 < p3))
|
|
{
|
|
p2 += 2;
|
|
sscanf(p2,"%d",&hnd->page_length);
|
|
hnd->page_length += 1;
|
|
}
|
|
p2 = strstr(p1,"W=");
|
|
if (p2 && (p2 < p3))
|
|
{
|
|
p2 += 2;
|
|
sscanf(p2,"%d",&hnd->page_width);
|
|
}
|
|
p2 = strstr(p1,"I=");
|
|
if (p2 && (p2 < p3))
|
|
{
|
|
p2 += 2;
|
|
sscanf(p2,"%s",hnd->background_image);
|
|
}
|
|
p3++;
|
|
if (*p3 == 10) p3++;
|
|
hnd->start_char = p3-p1;
|
|
do_linebreaks = false;
|
|
}
|
|
|
|
// Eliminate all <CR>'s so lines are delineated with <LF>'s only
|
|
p1 = hnd->buffer+hnd->start_char;
|
|
while (p1 < hnd->buffer+hnd->size)
|
|
{
|
|
if (*p1 == 13)
|
|
{
|
|
for (p2=p1, p3=p1+1; p2<hnd->buffer+hnd->size; p2++, p3++)
|
|
*p2 = *p3;
|
|
hnd->size--;
|
|
}
|
|
else
|
|
p1++;
|
|
}
|
|
// Count number of lines and replace all line feeds with 0's
|
|
hnd->nlines = 1;
|
|
for (p1 = hnd->buffer+hnd->start_char; p1 < hnd->buffer+hnd->size; p1++)
|
|
{
|
|
if (*p1 == 10)
|
|
{
|
|
hnd->nlines++;
|
|
*p1 = 0;
|
|
}
|
|
}
|
|
// Line break stuff
|
|
if (!do_linebreaks)
|
|
goto done_linebreaks;
|
|
|
|
line_length = 0;
|
|
p1 = hnd->buffer+hnd->start_char;
|
|
alt = false;
|
|
centered = false;
|
|
right_justified = false;
|
|
while (p1 < hnd->buffer+hnd->size)
|
|
{
|
|
// Don't count control characters
|
|
if (line_length == 0) {
|
|
if (*p1 == '*') {
|
|
p1++;
|
|
alt = true;
|
|
} else {
|
|
alt = false;
|
|
}
|
|
if (*p1 == '\\') {
|
|
p1++;
|
|
if (*p1 == 'c') {
|
|
p1++;
|
|
centered = true;
|
|
right_justified = false;
|
|
} else if (*p1 == 'r') {
|
|
p1++;
|
|
centered = false;
|
|
right_justified = true;
|
|
} else {
|
|
centered = false;
|
|
right_justified = false;
|
|
}
|
|
} else {
|
|
centered = false;
|
|
right_justified = false;
|
|
}
|
|
}
|
|
if ((line_length == 0) && (*p1 == '\\')) p1 += 2;
|
|
if (*p1 != 0) line_length++;
|
|
linebreak = false;
|
|
if (line_length > hnd->page_width)
|
|
{
|
|
if (*p1 == 32)
|
|
{
|
|
// We're at a space... good deal, just replace space with
|
|
// a line-break 0 and move on
|
|
*p1 = 0;
|
|
hnd->nlines++;
|
|
linebreak = true;
|
|
}
|
|
else
|
|
{
|
|
// back up from current position to last space character and
|
|
// replace with a 0 (but don't go past previous 0)
|
|
p2 = p1;
|
|
while (p1 > hnd->buffer+hnd->start_char && *p1 != 0)
|
|
{
|
|
if (*p1 == 32)
|
|
{
|
|
*p1 = 0;
|
|
hnd->nlines++;
|
|
linebreak = true;
|
|
}
|
|
else
|
|
p1--;
|
|
}
|
|
if (!linebreak) {
|
|
// Must be an ugly Mad Dog test trying my patience - say
|
|
// a 40-character line with no spaces. Back up one space,
|
|
// add a hyphen then a 0.
|
|
hnd->size += 2;
|
|
if (hnd->size >= hnd->allocated) {
|
|
hnd->allocated += 128;
|
|
temp_buffer = hnd->buffer;
|
|
hnd->buffer = gi.TagMalloc(hnd->allocated, TAG_LEVEL);
|
|
if (!hnd->buffer)
|
|
{
|
|
gi.dprintf("Memory allocation failure\n");
|
|
Text_Close(activator);
|
|
return;
|
|
}
|
|
memset(hnd->buffer,0,hnd->allocated);
|
|
memcpy(hnd->buffer,temp_buffer,hnd->size);
|
|
p1 = hnd->buffer + (p2-temp_buffer);
|
|
p2 = p1;
|
|
gi.TagFree(temp_buffer);
|
|
}
|
|
p1 = p2-1;
|
|
p2 = hnd->buffer + hnd->size;
|
|
p3 = p2 - 2;
|
|
while (p3 >= p1) {
|
|
*p2 = *p3;
|
|
p2--;
|
|
p3--;
|
|
}
|
|
*p1 = '-';
|
|
p1++;
|
|
*p1 = 0;
|
|
hnd->nlines++;
|
|
linebreak = true;
|
|
}
|
|
}
|
|
}
|
|
if (linebreak && alt) {
|
|
// We broke a line and the line was green text. Insert another
|
|
// '*' at beginning of next line
|
|
hnd->size += 1;
|
|
if (hnd->size > hnd->allocated) {
|
|
hnd->allocated += 128;
|
|
temp_buffer = hnd->buffer;
|
|
hnd->buffer = gi.TagMalloc(hnd->allocated, TAG_LEVEL);
|
|
if (!hnd->buffer)
|
|
{
|
|
gi.dprintf("Memory allocation failure\n");
|
|
Text_Close(activator);
|
|
return;
|
|
}
|
|
memset(hnd->buffer,0,hnd->allocated);
|
|
memcpy(hnd->buffer,temp_buffer,hnd->size);
|
|
p2 = p1;
|
|
p1 = hnd->buffer + (p2-temp_buffer);
|
|
gi.TagFree(temp_buffer);
|
|
}
|
|
p2 = hnd->buffer + hnd->size;
|
|
p3 = p2 - 1;
|
|
while (p3 >= p1) {
|
|
*p2 = *p3;
|
|
p2--;
|
|
p3--;
|
|
}
|
|
p2 = p1+1;
|
|
*p2 = '*';
|
|
}
|
|
if (linebreak && (centered || right_justified)) {
|
|
// We broke a line and the line had other than left justification. Insert another
|
|
// '\c' or '\r' at beginning of next line
|
|
hnd->size += 2;
|
|
if (hnd->size > hnd->allocated) {
|
|
hnd->allocated += 128;
|
|
temp_buffer = hnd->buffer;
|
|
hnd->buffer = gi.TagMalloc(hnd->allocated, TAG_LEVEL);
|
|
if (!hnd->buffer)
|
|
{
|
|
gi.dprintf("Memory allocation failure\n");
|
|
Text_Close(activator);
|
|
return;
|
|
}
|
|
memset(hnd->buffer,0,hnd->allocated);
|
|
memcpy(hnd->buffer,temp_buffer,hnd->size);
|
|
p2 = p1;
|
|
p1 = hnd->buffer + (p2-temp_buffer);
|
|
gi.TagFree(temp_buffer);
|
|
}
|
|
p2 = hnd->buffer + hnd->size;
|
|
p3 = p2 - 2;
|
|
while (p3 >= p1) {
|
|
*p2 = *p3;
|
|
p2--;
|
|
p3--;
|
|
}
|
|
p2 = p1+1;
|
|
if (alt) p2++;
|
|
*p2 = '\\';
|
|
p2++;
|
|
if (centered)
|
|
*p2 = 'c';
|
|
else
|
|
*p2 = 'r';
|
|
}
|
|
if (*p1=='\\') {
|
|
p2 = p1+1;
|
|
if (*p2=='n') {
|
|
*p1 = 0;
|
|
p3 = p2 + 1;
|
|
while (p3 < hnd->buffer + hnd->size) {
|
|
*p2 = *p3;
|
|
p2++;
|
|
p3++;
|
|
}
|
|
hnd->nlines++;
|
|
linebreak = true;
|
|
centered = false;
|
|
right_justified = false;
|
|
alt = false;
|
|
}
|
|
}
|
|
// If we're at a 0, check to see if subsequent words will fit on this line
|
|
if ((!linebreak) && (*p1 == 0) && (p1 < hnd->buffer+hnd->size-1) &&
|
|
(line_length < hnd->page_width) )
|
|
{
|
|
// Don't do this if 2 consecutive 0's are found (end of paragraph)
|
|
// or if 1st character in next line is '*' or '\'
|
|
p2 = p1;
|
|
p2--;
|
|
if (*p2 != 0)
|
|
{
|
|
p2++;
|
|
p2++;
|
|
if (*p2 != 0 && *p2 != '*' && *p2 != '\\' && p2 < hnd->buffer+hnd->size)
|
|
{
|
|
new_line_length = line_length+2;
|
|
while (p2 < hnd->buffer+hnd->size && *p2 != 32 && *p2 != 0)
|
|
{
|
|
new_line_length++;
|
|
p2++;
|
|
}
|
|
if (new_line_length <= hnd->page_width)
|
|
{
|
|
*p1 = 32;
|
|
line_length++; // include the space that was a 0
|
|
hnd->nlines--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (*p1 == 0) line_length = 0;
|
|
p1++;
|
|
}
|
|
|
|
done_linebreaks:
|
|
|
|
// Finally, scan for a \a code (embedded audio). If present remove that line
|
|
// and play the sound
|
|
p1 = hnd->buffer+hnd->start_char;
|
|
while (p1 < hnd->buffer+hnd->size)
|
|
{
|
|
if ((*p1 == 0) || (p1 == hnd->buffer+hnd->start_char))
|
|
{
|
|
if (*p1 == 0)
|
|
p1++;
|
|
if (*p1 == '\\')
|
|
{
|
|
p1++;
|
|
if (*p1 == 'a')
|
|
{
|
|
// strncpy(sound, p1+1);
|
|
Q_strncpyz(sound, p1+1, sizeof(sound));
|
|
p1--;
|
|
p2=p1;
|
|
while (*p2 != 0)
|
|
p2++;
|
|
p2++;
|
|
memcpy(p1,p2,hnd->buffer+hnd->size-p2+1);
|
|
hnd->nlines--;
|
|
// Found one (only one is allowed)
|
|
gi.sound (activator, CHAN_AUTO, gi.soundindex (sound), 1, ATTN_NORM, 0);
|
|
}
|
|
}
|
|
}
|
|
p1++;
|
|
}
|
|
|
|
hnd->curline = 0;
|
|
hnd->flags = flags;
|
|
Text_BuildDisplay(hnd);
|
|
hnd->lines = text;
|
|
activator->client->textdisplay = hnd;
|
|
Text_Open(activator);
|
|
|
|
}
|
|
|
|
void Use_Target_Text(edict_t *self, edict_t *other, edict_t *activator)
|
|
{
|
|
|
|
if (!activator || !activator->client) return;
|
|
activator->client->showinventory = false;
|
|
activator->client->showscores = false;
|
|
activator->client->showhelp = false;
|
|
|
|
Text_Close(activator);
|
|
|
|
Do_Text_Display(activator, self->spawnflags, self->message);
|
|
|
|
}
|
|
|
|
void SP_target_text(edict_t *self)
|
|
{
|
|
if (!self->message)
|
|
{
|
|
gi.dprintf("target_text with no message at %s\n",
|
|
vtos(self->s.origin));
|
|
G_FreeEdict (self);
|
|
return;
|
|
}
|
|
self->class_id = ENTITY_TARGET_TEXT;
|
|
self->use = Use_Target_Text;
|
|
}
|
|
|
|
|