openmohaa/code/qcommon/alias.c
smallmodel 9d4ea75a18
Increase the number of aliases that can be found
Previously, 64 aliases could be chosen for random search, it was incremented to 128 since 2.0, however it should have been increased in Breakthrough as well, because there are aliases with more than 128 elements
2024-12-19 19:19:12 +01:00

684 lines
18 KiB
C

/*
===========================================================================
Copyright (C) 2024 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA 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.
OpenMoHAA 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 OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "q_shared.h"
#include "qcommon.h"
#include "alias.h"
static AliasList_t *Aliases;
//static AliasListNode_t* foundlist[64];
// Changed in 2.0
//static AliasListNode_t* foundlist[128];
// Changed in OPM
static AliasListNode_t *foundlist[256];
AliasListNode_t *AliasListNode_New()
{
AliasListNode_t *node = Z_TagMalloc(sizeof(AliasListNode_t), TAG_TIKI);
memset(node, 0, sizeof(AliasListNode_t));
node->weight = 1.0f;
node->next = NULL;
return node;
}
AliasList_t *AliasList_New(const char *name)
{
AliasList_t *list = Z_TagMalloc(sizeof(AliasList_t), TAG_TIKI);
list->num_in_list = 0;
list->sorted_list = NULL;
list->data_list = NULL;
list->dirty = qfalse;
if (name) {
strncpy(list->name, name, sizeof(list->name));
} else {
list->name[0] = 0;
}
return list;
}
void Alias_ListClear(AliasList_t *list)
{
AliasListNode_t *node;
AliasListNode_t *next;
if (list->sorted_list) {
Z_Free(list->sorted_list);
}
for (node = list->data_list; node != NULL; node = next) {
next = node->next;
Z_Free(node);
}
list->num_in_list = 0;
list->dirty = qfalse;
list->sorted_list = NULL;
list->data_list = NULL;
}
void Alias_ListDelete(AliasList_t *list)
{
Alias_ListClear(list);
Z_Free(list);
}
float getTokenFloat(const char **parameters, char *parmName, AliasListNode_t *node)
{
const char *token;
float temp_float = 0.0f;
token = COM_GetToken((char **)parameters, 1);
if (token && *token) {
temp_float = (float)atof(token);
if (temp_float < 0.0f) {
Com_Printf("ERROR getTokenFloat: %s value out of range in %s alias\n", parmName, node->alias_name);
}
return temp_float;
} else {
Com_Printf("ERROR getTokenFloat: %s value is hosed or wasn't found for %s\n", parmName, node->alias_name);
}
return 0.0f;
}
int S_ChannelNameToNum(const char *pszName)
{
if (!Q_stricmp(pszName, "auto")) {
return CHAN_AUTO;
} else if (!Q_stricmp(pszName, "local")) {
return CHAN_LOCAL;
} else if (!Q_stricmp(pszName, "weapon")) {
return CHAN_WEAPON;
} else if (!Q_stricmp(pszName, "voice")) {
return CHAN_VOICE;
} else if (!Q_stricmp(pszName, "item")) {
return CHAN_ITEM;
} else if (!Q_stricmp(pszName, "body")) {
return CHAN_BODY;
} else if (!Q_stricmp(pszName, "dialog")) {
return CHAN_DIALOG;
} else if (!Q_stricmp(pszName, "dialog_secondary")) {
return CHAN_DIALOG_SECONDARY;
} else if (!Q_stricmp(pszName, "weaponidle")) {
return CHAN_WEAPONIDLE;
} else if (!Q_stricmp(pszName, "menu")) {
return CHAN_MENU;
} else {
return -1;
}
}
const char *S_ChannelNumToName(int iChannel)
{
switch (iChannel) {
case CHAN_AUTO:
return "auto";
case CHAN_LOCAL:
return "local";
case CHAN_WEAPON:
return "weapon";
case CHAN_VOICE:
return "voice";
case CHAN_ITEM:
return "item";
case CHAN_BODY:
return "body";
case CHAN_DIALOG:
return "dialog";
case CHAN_DIALOG_SECONDARY:
return "dialog_secondary";
case CHAN_WEAPONIDLE:
return "weaponidle";
case CHAN_MENU:
return "menu";
default:
return NULL;
}
}
void Alias_ListAddParms(AliasListNode_t *node, const char *parameters)
{
const char *token;
float temp_float;
const char *nptr;
if (!node || !parameters) {
return;
}
for (;;) {
token = nptr = COM_GetToken((char **)&parameters, qtrue);
if (!token || !token[0]) {
break;
}
if (!Q_stricmp(token, "stop")) {
node->stop_flag = 1;
} else if (!Q_stricmp(token, "soundparms")) {
node->volume = getTokenFloat(&parameters, "volume", node);
node->volumeMod = getTokenFloat(&parameters, "volumeMod", node);
node->pitch = getTokenFloat(&parameters, "pitch", node);
node->pitchMod = getTokenFloat(&parameters, "pitchMod", node);
node->dist = getTokenFloat(&parameters, "dist", node);
node->maxDist = getTokenFloat(&parameters, "maxDist", node);
token = COM_GetToken((char **)&parameters, qtrue);
if (!token || !*token) {
return;
}
node->channel = S_ChannelNameToNum(token);
if (node->channel == -1) {
Com_Printf("%s is not avalid channel on %s alias.\n", token, node->alias_name);
node->channel = 0;
}
token = COM_GetToken((char **)&parameters, qtrue);
if (!token || !*token) {
Com_Printf("ERROR: defaulting %s to not streamed - please setup alias properly.\n", node->alias_name);
return;
}
if (!Q_stricmp(token, "streamed")) {
node->streamed = qtrue;
} else if (!Q_stricmp(token, "loaded")) {
node->streamed = qfalse;
} else {
Com_Printf(
"ERROR: Expecting streamed or loaded in ubersound and got %s on alias %s\n", token, node->alias_name
);
continue;
}
} else if (!Q_stricmp(token, "subtitle") || !Q_stricmp(token, "forcesubtitle")) {
size_t size;
if (!Q_stricmp(token, "subtitle")) {
node->forcesubtitle = qfalse;
} else {
node->forcesubtitle = qtrue;
}
token = COM_GetToken((char **)&parameters, qtrue);
if (!token || !*token) {
Com_Printf("NULL subtitle on %s alias.\n", node->alias_name);
return;
}
size = strlen(token) + 1;
node->subtitle = Z_TagMalloc(size, TAG_TIKI);
memcpy(node->subtitle, token, size);
} else if (!Q_stricmp(token, "pitch")) {
token = COM_GetToken((char **)&parameters, qtrue);
if (!token || !*token) {
return;
}
temp_float = (float)atof(token);
if (temp_float < 0.0f) {
Com_Printf("Pitch value out of range in %s alias\n", node->alias_name);
continue;
}
node->pitch = temp_float;
} else if (!Q_stricmp(token, "pitchmod")) {
token = COM_GetToken((char **)&parameters, qtrue);
if (!token || !*token) {
return;
}
temp_float = (float)atof(token);
if (temp_float < 0.0f) {
Com_Printf("PitchMod value out of range in %s alias\n", node->alias_name);
continue;
}
node->pitchMod = temp_float;
} else if (!Q_stricmp(token, "volumemod")) {
token = COM_GetToken((char **)&parameters, qtrue);
if (!token || !*token) {
return;
}
temp_float = (float)atof(token);
if (temp_float < 0.0f) {
Com_Printf("volumeMod value out of range in %s alias\n", node->alias_name);
continue;
}
node->volumeMod = temp_float;
} else if (!Q_stricmp(token, "dist")) {
token = COM_GetToken((char **)&parameters, qtrue);
if (!token || !*token) {
Com_Printf("\n\n BAD DISTANCE\n\n");
return;
}
temp_float = (float)atof(token);
if (temp_float < 0.0f) {
Com_Printf("dist value out of range in %s alias\n", node->alias_name);
continue;
}
node->dist = temp_float;
} else if (!Q_stricmp(token, "channel")) {
token = COM_GetToken((char **)&parameters, qtrue);
if (!token || !*token) {
Com_Printf("\n\n BAD DISTANCE\n\n");
return;
}
node->channel = S_ChannelNameToNum(token);
if (node->channel == -1) {
Com_Printf("%s is not a valid channel on %s alias.\n", token, node->alias_name);
node->channel = CHAN_AUTO;
}
} else {
Com_Printf("Unknown parameter for %s alias\n", node->alias_name);
continue;
}
}
}
qboolean Alias_ListAdd(AliasList_t *list, const char *alias, const char *name, const char *parameters)
{
AliasListNode_t *ptr = NULL;
int i;
AliasListNode_t *node;
if (!list) {
return qfalse;
}
if (list->dirty) {
for (node = list->data_list; node != NULL; node = node->next) {
if (!strcmp(node->alias_name, alias)) {
Com_DPrintf("DUPLICATE ALIASES: %s and %s\n", node->alias_name, alias);
return qtrue;
}
}
} else {
ptr = Alias_ListFindNode(list, alias);
}
if (!ptr) {
node = AliasListNode_New();
strncpy(node->alias_name, alias, sizeof(node->alias_name));
for (i = 0; i < MAX_ALIASLIST_NAME_LENGTH; i++) {
node->alias_name[i] = tolower(node->alias_name[i]);
}
strncpy(node->real_name, name, sizeof(node->real_name));
node->stop_flag = 0;
Alias_ListAddParms(node, parameters);
list->dirty = qtrue;
list->num_in_list++;
node->next = list->data_list;
list->data_list = node;
} else if (strcmp(name, ptr->real_name)) {
Com_DPrintf("Duplicate Aliases for %s in list %s.\n", alias, name);
}
return qtrue;
}
void Alias_ListSort(AliasList_t *list)
{
int num;
int size;
int i;
AliasListNode_t *root;
AliasListNode_t *ptr;
AliasListNode_t *smallest = NULL;
AliasListNode_t *prev;
AliasListNode_t *smallprev;
AliasListNode_t *last = NULL;
if (!list->dirty) {
return;
}
num = 0;
root = list->data_list;
list->data_list = NULL;
if (list->sorted_list) {
Z_Free(list->sorted_list);
}
size = list->num_in_list * sizeof(AliasListNode_t *);
list->sorted_list = Z_TagMalloc(size, TAG_TIKI);
memset(list->sorted_list, 0, size);
for (i = 0; i < list->num_in_list; i++) {
prev = root;
smallprev = root;
for (ptr = root->next; ptr != NULL; ptr = ptr->next) {
if (strcmp(ptr->alias_name, smallprev->alias_name) < 0) {
smallest = prev;
smallprev = ptr;
}
prev = ptr;
}
if (smallprev == root) {
root = smallprev->next;
} else {
smallest->next = smallprev->next;
}
if (!last || strcmp(last->alias_name, smallprev->alias_name)) {
list->sorted_list[num++] = smallprev;
smallprev->next = list->data_list;
list->data_list = smallprev;
last = smallprev;
} else {
if (strcmp(last->real_name, smallprev->real_name)) {
Com_DPrintf("Duplicate Aliases for %s in list %s Last: %p.\n", last->alias_name, list->name, last);
}
Z_Free(smallprev);
}
}
list->dirty = 0;
list->num_in_list = num;
}
const char *Alias_ListFind(AliasList_t *list, const char *alias)
{
AliasListNode_t *node = Alias_ListFindNode(list, alias);
if (node) {
return node->real_name;
} else {
return NULL;
}
}
void Alias_ListUpdateDialog(AliasList_t *list, const char *alias)
{
int min_index;
int max_index;
float total_weight;
Alias_ListFindRandomRange(list, alias, &min_index, &max_index, &total_weight);
}
AliasListNode_t *Alias_ListFindNode(AliasList_t *list, const char *alias)
{
char convalias[40];
int index;
int l;
int r;
int diff;
size_t length;
int __res;
if (list->dirty) {
Alias_ListSort(list);
}
length = strlen(alias);
for (index = 0; index < length; index++) {
convalias[index] = tolower(alias[index]);
}
convalias[length] = 0;
r = 0;
l = list->num_in_list - 1;
for (index = l; index >= 0; index--) {
__res = (l + r) >> 1;
diff = strcmp(convalias, list->sorted_list[index]->alias_name);
if (diff == 0) {
return list->sorted_list[index];
} else if (diff > 0) {
r = __res + 1;
} else {
l = __res - 1;
}
}
return NULL;
}
float randweight()
{
return ((float)(rand() & 0x7fff)) / ((float)0x8000);
}
const char *Alias_ListFindRandom(AliasList_t *list, const char *alias, AliasListNode_t **ret)
{
int min_index;
int max_index;
float total_weight;
int i;
int numfound;
float weight;
float num;
if (!*alias) {
return NULL;
}
Alias_ListFindRandomRange(list, alias, &min_index, &max_index, &total_weight);
if (min_index == -1 || max_index == -1) {
return NULL;
}
num = 0.0f;
numfound = max_index - min_index + 1;
weight = randweight() * total_weight;
for (i = 0; i < numfound; i++) {
num += list->sorted_list[i + min_index]->weight;
if (num > weight) {
if (ret) {
*ret = list->sorted_list[i + min_index];
}
return list->sorted_list[i + min_index]->real_name;
}
}
return NULL;
}
void Alias_ListFindRandomRange(
AliasList_t *list, const char *alias, int *min_index, int *max_index, float *total_weight
)
{
char convalias[MAX_ALIASLIST_NAME_LENGTH];
int index;
int l;
int r;
int diff;
int i;
size_t length;
int numfound;
float totalfoundweight = 0.0f;
AliasListNode_t **ptr;
*min_index = -1;
*max_index = -1;
if (!*alias) {
return;
}
if (list->dirty) {
Alias_ListSort(list);
}
length = strlen(alias);
if (length > MAX_ALIASLIST_NAME_LENGTH) {
return;
}
for (index = 0; index < length; index++) {
convalias[index] = tolower(alias[index]);
}
convalias[length] = 0;
l = 0;
r = list->num_in_list - 1;
if (r >= 0) {
do {
index = (l + r) >> 1;
diff = strncmp(convalias, list->sorted_list[index]->alias_name, length);
if (diff == 0) {
break;
} else if (diff > 0) {
l = index + 1;
} else {
r = index - 1;
}
} while (r >= l);
if (r >= l) {
numfound = 0;
*min_index = index;
*max_index = index;
totalfoundweight = 0.f;
ptr = &list->sorted_list[index];
for (i = index + 1; i > 0; i--, ptr--) {
if (strncmp(convalias, (*ptr)->alias_name, length)) {
break;
}
if (numfound < ARRAY_LEN(foundlist) && (*ptr)->alias_name[length] != '_') {
foundlist[numfound++] = *ptr;
totalfoundweight += (*ptr)->weight;
*min_index = i - 1;
}
}
ptr = &list->sorted_list[index + 1];
for (i = index + 1; i < list->num_in_list; i++, ptr++) {
if (strncmp(convalias, (*ptr)->alias_name, length)) {
break;
}
if (numfound < ARRAY_LEN(foundlist) && (*ptr)->alias_name[length] != '_') {
foundlist[numfound++] = *ptr;
totalfoundweight += (*ptr)->weight;
*max_index = i;
}
}
if (numfound) {
*total_weight = totalfoundweight;
} else {
*min_index = -1;
*max_index = -1;
}
}
}
}
void Alias_ListDump(AliasList_t *list)
{
AliasListNode_t *ptr;
int i;
if (list->dirty) {
Alias_ListSort(list);
}
Com_DPrintf("Alias List: %s\n", list->name);
Com_DPrintf("Alias Name / Weight / Real Name\n");
for (i = 0; i < list->num_in_list; ++i) {
ptr = list->sorted_list[i];
Com_DPrintf("%32s %3.2f %s\n", ptr->alias_name, ptr->weight, ptr->real_name);
}
Com_DPrintf("%d total aliases\n", list->num_in_list);
}
const char *Alias_Find(const char *alias)
{
if (!Aliases) {
Aliases = AliasList_New("Global");
}
return Alias_ListFind(Aliases, alias);
}
qboolean Alias_Add(const char *alias, const char *name, const char *parameters)
{
if (!Aliases) {
Aliases = AliasList_New("Global");
}
return Alias_ListAdd(Aliases, alias, name, parameters);
}
qboolean Alias_Delete(const char *alias)
{
return qtrue;
}
const char *Alias_FindRandom(const char *alias, AliasListNode_t **ret)
{
if (!Aliases) {
Aliases = AliasList_New("Global");
}
return Alias_ListFindRandom(Aliases, alias, ret);
}
void Alias_Dump()
{
if (!Aliases) {
Aliases = AliasList_New("Global");
}
Alias_ListDump(Aliases);
}
void Alias_Clear()
{
if (!Aliases) {
Aliases = AliasList_New("Global");
}
Alias_ListClear(Aliases);
}
AliasList_t *Alias_GetGlobalList()
{
return Aliases;
}