/* ============= G_NewString Builds a copy of the string, translating \n to real linefeeds so message texts can be multi-line ============= */ char *G_NewString( const char *string ) { char *newb, *new_p; int i,l; l = strlen(string) + 1; newb = trap_Alloc( l, NULL ); new_p = newb; // turn \n into a real linefeed for ( i=0 ; i< l ; i++ ) { if (string[i] == '\\' && i < l-1) { i++; if (string[i] == 'n') { *new_p++ = '\n'; } else { *new_p++ = '\\'; } } else { *new_p++ = string[i]; } } return newb; }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void BotDefaultCharacteristics(bot_character_t *ch, bot_character_t *defaultch) { int i; for (i = 0; i < MAX_CHARACTERISTICS; i++) { if (ch->c[i].type) continue; // if (defaultch->c[i].type == CT_FLOAT) { ch->c[i].type = CT_FLOAT; ch->c[i].value._float = defaultch->c[i].value._float; } //end if else if (defaultch->c[i].type == CT_INTEGER) { ch->c[i].type = CT_INTEGER; ch->c[i].value.integer = defaultch->c[i].value.integer; } //end else if else if (defaultch->c[i].type == CT_STRING) { ch->c[i].type = CT_STRING; ch->c[i].value.string = (char *) trap_Alloc(strlen(defaultch->c[i].value.string)+1, NULL); strcpy(ch->c[i].value.string, defaultch->c[i].value.string); } //end else if } //end for } //end of the function BotDefaultCharacteristics
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int BotInterpolateCharacters(int handle1, int handle2, float desiredskill) { bot_character_t *ch1, *ch2, *out; int i, handle; float scale; ch1 = BotCharacterFromHandle(handle1); ch2 = BotCharacterFromHandle(handle2); if (!ch1 || !ch2) return 0; //find a free spot for a character for (handle = 1; handle < MAX_BOT_CHARACTERS; handle++) { if (!botcharacters[handle].skill) break; } //end for if (handle >= MAX_BOT_CHARACTERS) return 0; out = &botcharacters[handle]; out->skill = desiredskill; strcpy(out->filename, ch1->filename); scale = (float) (desiredskill - ch1->skill) / (ch2->skill - ch1->skill); for (i = 0; i < MAX_CHARACTERISTICS; i++) { // if (ch1->c[i].type == CT_FLOAT && ch2->c[i].type == CT_FLOAT) { out->c[i].type = CT_FLOAT; out->c[i].value._float = ch1->c[i].value._float + (ch2->c[i].value._float - ch1->c[i].value._float) * scale; } //end if else if (ch1->c[i].type == CT_INTEGER) { out->c[i].type = CT_INTEGER; out->c[i].value.integer = ch1->c[i].value.integer; } //end else if else if (ch1->c[i].type == CT_STRING) { out->c[i].type = CT_STRING; out->c[i].value.string = (char *) trap_Alloc(strlen(ch1->c[i].value.string)+1, NULL); strcpy(out->c[i].value.string, ch1->c[i].value.string); } //end else if } //end for return handle; } //end of the function BotInterpolateCharacters
/* ============== BotAISetupPlayer ============== */ int BotAISetupPlayer(int playernum, struct bot_settings_s *settings, qboolean restart) { char filename[MAX_PATH], name[MAX_PATH], gender[MAX_PATH]; bot_state_t *bs; int errnum; if (!botstates[playernum]) botstates[playernum] = trap_Alloc(sizeof(bot_state_t), NULL); bs = botstates[playernum]; if (!bs) { return qfalse; } if (bs && bs->inuse) { BotAI_Print(PRT_FATAL, "BotAISetupPlayer: player %d already setup\n", playernum); return qfalse; } if (!trap_AAS_Initialized()) { BotAI_Print(PRT_FATAL, "AAS not initialized\n"); return qfalse; } //load the bot character bs->character = BotLoadCharacter(settings->characterfile, settings->skill); if (!bs->character) { BotAI_Print(PRT_FATAL, "couldn't load skill %f from %s\n", settings->skill, settings->characterfile); return qfalse; } //copy the settings memcpy(&bs->settings, settings, sizeof(bot_settings_t)); //allocate a goal state bs->gs = BotAllocGoalState(playernum); //load the item weights Characteristic_String(bs->character, CHARACTERISTIC_ITEMWEIGHTS, filename, MAX_PATH); errnum = BotLoadItemWeights(bs->gs, filename); if (errnum != BLERR_NOERROR) { BotFreeGoalState(bs->gs); BotAI_Print(PRT_FATAL, "BotLoadItemWeights failed\n"); return qfalse; } //allocate a weapon state bs->ws = BotAllocWeaponState(playernum); //load the weapon weights Characteristic_String(bs->character, CHARACTERISTIC_WEAPONWEIGHTS, filename, MAX_PATH); errnum = BotLoadWeaponWeights(bs->ws, filename); if (errnum != BLERR_NOERROR) { BotFreeGoalState(bs->gs); BotFreeWeaponState(bs->ws); BotAI_Print(PRT_FATAL, "BotLoadWeaponWeights failed\n"); return qfalse; } //allocate a chat state bs->cs = BotAllocChatState(); //load the chat file Characteristic_String(bs->character, CHARACTERISTIC_CHAT_FILE, filename, MAX_PATH); Characteristic_String(bs->character, CHARACTERISTIC_CHAT_NAME, name, MAX_PATH); errnum = BotLoadChatFile(bs->cs, filename, name); if (errnum != BLERR_NOERROR) { BotFreeChatState(bs->cs); BotFreeGoalState(bs->gs); BotFreeWeaponState(bs->ws); BotAI_Print(PRT_FATAL, "BotLoadChatFile failed\n"); return qfalse; } //get the gender characteristic Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, MAX_PATH); //set the chat gender if (*gender == 'f' || *gender == 'F') BotSetChatGender(bs->cs, CHAT_GENDERFEMALE); else if (*gender == 'm' || *gender == 'M') BotSetChatGender(bs->cs, CHAT_GENDERMALE); else BotSetChatGender(bs->cs, CHAT_GENDERLESS); bs->inuse = qtrue; bs->playernum = playernum; bs->entitynum = playernum; bs->setupcount = 4; bs->entergame_time = FloatTime(); bs->ms = BotAllocMoveState(playernum); bs->walker = Characteristic_BFloat(bs->character, CHARACTERISTIC_WALKER, 0, 1); bs->revenge_enemy = -1; numbots++; trap_Cvar_Update( &bot_testichat ); if (bot_testichat.integer) { BotChatTest(bs); } //NOTE: reschedule the bot thinking BotScheduleBotThink(); //if interbreeding start with a mutation if (bot_interbreed) { BotMutateGoalFuzzyLogic(bs->gs, 1); } // if we kept the bot state if (restart) { BotReadSessionData(bs); } //bot has been setup succesfully return qtrue; }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== qboolean BotLoadCharacterFromFile(char *charfile, int skill, bot_character_t *ch) { int indent, index, foundcharacter; int source; pc_token_t token; foundcharacter = qfalse; //a bot character is parsed in two phases source = trap_PC_LoadSource(charfile, BOTFILESBASEFOLDER); if (!source) { BotAI_Print(PRT_ERROR, "counldn't load %s\n", charfile); return qfalse; } //end if strcpy(ch->filename, charfile); while(trap_PC_ReadToken(source, &token)) { if (!strcmp(token.string, "skill")) { if (!PC_ExpectTokenType(source, TT_NUMBER, 0, &token)) { trap_PC_FreeSource(source); BotFreeCharacterStrings(ch); return qfalse; } //end if if (!PC_ExpectTokenString(source, "{")) { trap_PC_FreeSource(source); BotFreeCharacterStrings(ch); return qfalse; } //end if //if it's the correct skill if (skill < 0 || token.intvalue == skill) { foundcharacter = qtrue; ch->skill = token.intvalue; while(PC_ExpectAnyToken(source, &token)) { if (!strcmp(token.string, "}")) break; if (token.type != TT_NUMBER || !(token.subtype & TT_INTEGER)) { PC_SourceError(source, "expected integer index, found %s", token.string); trap_PC_FreeSource(source); BotFreeCharacterStrings(ch); return qfalse; } //end if index = token.intvalue; if (index < 0 || index > MAX_CHARACTERISTICS) { PC_SourceError(source, "characteristic index out of range [0, %d]", MAX_CHARACTERISTICS); trap_PC_FreeSource(source); BotFreeCharacterStrings(ch); return qfalse; } //end if if (ch->c[index].type) { PC_SourceError(source, "characteristic %d already initialized", index); trap_PC_FreeSource(source); BotFreeCharacterStrings(ch); return qfalse; } //end if if (!PC_ExpectAnyToken(source, &token)) { trap_PC_FreeSource(source); BotFreeCharacterStrings(ch); return qfalse; } //end if if (token.type == TT_NUMBER) { if (token.subtype & TT_FLOAT) { ch->c[index].value._float = token.floatvalue; ch->c[index].type = CT_FLOAT; } //end if else { ch->c[index].value.integer = token.intvalue; ch->c[index].type = CT_INTEGER; } //end else } //end if else if (token.type == TT_STRING) { // ZTM: FIXME: ### I think I made this be done in the engine //StripDoubleQuotes(token.string); ch->c[index].value.string = trap_Alloc(strlen(token.string)+1, NULL); strcpy(ch->c[index].value.string, token.string); ch->c[index].type = CT_STRING; } //end else if else { PC_SourceError(source, "expected integer, float or string, found %s", token.string); trap_PC_FreeSource(source); BotFreeCharacterStrings(ch); return qfalse; } //end else } //end if break; } //end if else { indent = 1; while(indent) { if (!PC_ExpectAnyToken(source, &token)) { trap_PC_FreeSource(source); BotFreeCharacterStrings(ch); return qfalse; } //end if if (!strcmp(token.string, "{")) indent++; else if (!strcmp(token.string, "}")) indent--; } //end while } //end else } //end if else { PC_SourceError(source, "unknown definition %s", token.string); trap_PC_FreeSource(source); BotFreeCharacterStrings(ch); return qfalse; } //end else } //end while trap_PC_FreeSource(source); // if (!foundcharacter) { BotFreeCharacterStrings(ch); return qfalse; } //end if return qtrue; } //end of the function BotLoadCharacterFromFile