void CServer::BotCreate(struct bot_profile_s *profile) { edict_t *BotEnt = CreateFakeClient(profile->name); if (!FNullEnt(BotEnt)) { char *infobuffer = GET_INFOBUFFER(BotEnt); int clientIndex = ENTINDEX(BotEnt); CBaseBot *pBot = NewBotInstance(); pBot->pev = &BotEnt->v; pBot->m_pProfile = profile; if (!IsTeamplay()) { SET_CLIENT_KEY_VALUE(clientIndex, infobuffer, "model", profile->skin); // use random colors SET_CLIENT_KEY_VALUE(clientIndex, infobuffer, "topcolor", va("%d", RandomLong(0, 255))); SET_CLIENT_KEY_VALUE(clientIndex, infobuffer, "bottomcolor", va("%d", RandomLong(0, 255))); } AddBot(pBot); pBot->m_pProfile->is_used = true; } }
const char *CChatItem::PickMessage() { assert(msg.size()); // just pick a random message from the list return msg[RandomLong(0, msg.size() - 1)].c_str(); }
// Decide who the landlord is. int CGame::Bidding() { int iRandomLord = RandomLong(0, 2), c = 0, h = 0; m_iCurLord = -1; while (c < 3 && h <= 3) { int index = iRandomLord - c; if (index < 0) { index += 3; } m_rgpPlayers[0]->Turn(RL(index, 0)); m_rgpPlayers[1]->Turn(RL(index, 1)); m_rgpPlayers[2]->Turn(RL(index, 2)); int s = GetPlayer(index)->Bid(h); if (s < h) { s = 0; } m_rgpPlayers[0]->PlayerBidded(RL(index, 0), s); m_rgpPlayers[1]->PlayerBidded(RL(index, 1), s); m_rgpPlayers[2]->PlayerBidded(RL(index, 2), s); if (s >= h) { m_iCurLord = index; h = s + 1; } c++; } return h - 1; }
const char *CChatReply::PickMessage(void) { if (msg.size() <= 0) return NULL; // reliability check // just pick a random message from the list return msg[RandomLong(0, msg.size() - 1)].c_str(); }
SHORT PAL_CalcMagicDamage( WORD wMagicStrength, WORD wDefense, const WORD rgwElementalResistance[NUM_MAGIC_ELEMENTAL], WORD wMagicID ) /*++ Purpose: Calculate the damage of magic. Parameters: [IN] wMagicStrength - magic strength of attacker. [IN] wDefense - defense value of inflictor. [IN] rgwAttribResistance - inflictor's resistance to the attributed magics. [IN] wMagicID - object ID of the magic. Return value: The damage value of the magic attack. --*/ { SHORT sDamage; WORD wElem; wMagicID = gpGlobals->g.rgObject[wMagicID].magic.wMagicNumber; // // Formula courtesy of palxex and shenyanduxing // wMagicStrength *= RandomLong(9, 11); wMagicStrength /= 10; sDamage = PAL_CalcBaseDamage(wMagicStrength, wDefense) / 2; sDamage += gpGlobals->g.lprgMagic[wMagicID].wBaseDamage; if (gpGlobals->g.lprgMagic[wMagicID].wElemental != 0) { wElem = gpGlobals->g.lprgMagic[wMagicID].wElemental - 1; sDamage *= 10 - rgwElementalResistance[wElem]; sDamage /= 5; if (wElem < NUM_MAGIC_ELEMENTAL) { sDamage *= 10 + gpGlobals->g.lprgBattleField[gpGlobals->wNumBattleField].rgsMagicEffect[wElem]; sDamage /= 10; } } return sDamage; }
// this function gets called when the client "from" sends a chat message "message" // to the client "to" void CChatManager::ChatMessage(CClient *from, CClient *to, const char *message) { if (!to->IsBot()) return; // ignore this message if the destination is NOT a bot CBaseBot *pBot = (CBaseBot *)to; if (!pBot->Chat()->IsGoodChatPosition()) return; // not a good chat position; don't proceed // only process the message randomly, don't reply to every message if (RandomLong(1, 100) < 50) pBot->Chat()->ReplyToMessage(from, message); }
void Sys_GetCDKey(char *pszCDKey, int *nLength, int *bDedicated) { char key[65]; char hostname[4096]; if (CRehldsPlatformHolder::get()->gethostname(hostname, sizeof(hostname))) Q_snprintf(key, sizeof(key), "%u", RandomLong(0, 0x7FFFFFFF)); else { struct hostent *hostinfo; hostinfo = CRehldsPlatformHolder::get()->gethostbyname(hostname); if (hostinfo && hostinfo->h_length == 4 && *hostinfo->h_addr_list != NULL) { Q_snprintf(key, sizeof(key), "%u.%u.%u.%u", (*hostinfo->h_addr_list)[0], (*hostinfo->h_addr_list)[1], (*hostinfo->h_addr_list)[2], (*hostinfo->h_addr_list)[3]); } else { CRC32_t crc; #ifdef REHLDS_FIXES crc = 0; #endif CRC32_ProcessBuffer(&crc, hostname, Q_strlen(hostname)); Q_snprintf(key, sizeof(key), "%u", crc); } } key[64] = 0; Q_strcpy(pszCDKey, key); if (nLength) *nLength = Q_strlen(key); if (bDedicated) *bDedicated = 0; }
/*++ Increase the player's level by wLevels. Parameters: [IN] wPlayerRole - player role ID. [IN] wNumLevel - number of levels to be increased. --*/ VOID PAL_PlayerLevelUp(WORD wPlayerRole, WORD wNumLevel) { WORD i; // // Add the level // gpGlobals->g.PlayerRoles.rgwLevel[wPlayerRole] += wNumLevel; if (gpGlobals->g.PlayerRoles.rgwLevel[wPlayerRole] > MAX_LEVELS) { gpGlobals->g.PlayerRoles.rgwLevel[wPlayerRole] = MAX_LEVELS; } for (i = 0; i < wNumLevel; i++) { // // Increase player's stats // gpGlobals->g.PlayerRoles.rgwMaxHP[wPlayerRole] += 10 + RandomLong(0, 8); gpGlobals->g.PlayerRoles.rgwMaxMP[wPlayerRole] += 8 + RandomLong(0, 6); gpGlobals->g.PlayerRoles.rgwAttackStrength[wPlayerRole] += 4 + RandomLong(0, 1); gpGlobals->g.PlayerRoles.rgwMagicStrength[wPlayerRole] += 4 + RandomLong(0, 1); gpGlobals->g.PlayerRoles.rgwDefense[wPlayerRole] += 2 + RandomLong(0, 1); gpGlobals->g.PlayerRoles.rgwDexterity[wPlayerRole] += 2 + RandomLong(0, 1); gpGlobals->g.PlayerRoles.rgwFleeRate[wPlayerRole] += 2; } #define STAT_LIMIT(t) { if ((t) > MAX_PROPERTY_VALUE) (t) = MAX_PROPERTY_VALUE; } STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwMaxHP[wPlayerRole]); STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwMaxMP[wPlayerRole]); STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwAttackStrength[wPlayerRole]); STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwMagicStrength[wPlayerRole]); STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwDefense[wPlayerRole]); STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwDexterity[wPlayerRole]); STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwFleeRate[wPlayerRole]); #undef STAT_LIMIT // // Reset experience points to zero // gpGlobals->Exp.rgPrimaryExp[wPlayerRole].wExp = 0; gpGlobals->Exp.rgPrimaryExp[wPlayerRole].wLevel = gpGlobals->g.PlayerRoles.rgwLevel[wPlayerRole]; }
/* <d38ba> ../engine/net_ws.c:784 */ qboolean NET_LagPacket(qboolean newdata, netsrc_t sock, netadr_t *from, sizebuf_t *data) { packetlag_t *pNewPacketLag; packetlag_t *pPacket; float curtime; int ninterval; static int losscount[3]; if (gFakeLag <= 0.0) { NET_ClearLagData(TRUE, TRUE); return newdata; } curtime = realtime; if (newdata) { if (fakeloss.value != 0.0) { if (allow_cheats) { ++losscount[sock]; if (fakeloss.value <= 0.0f) { ninterval = fabs(fakeloss.value); if (ninterval < 2) ninterval = 2; if ((losscount[sock] % ninterval) == 0) return FALSE; } else { if (RandomLong(0, 100) <= fakeloss.value) return FALSE; } } else { Cvar_SetValue("fakeloss", 0.0); } } pNewPacketLag = (packetlag_t *)Mem_ZeroMalloc(0x28u); NET_AddToLagged(sock, &g_pLagData[sock], pNewPacketLag, from, *data, curtime); } pPacket = g_pLagData[sock].pNext; while (pPacket != &g_pLagData[sock]) { if (pPacket->receivedTime <= curtime - gFakeLag / 1000.0) break; pPacket = pPacket->pNext; } if (pPacket == &g_pLagData[sock]) return FALSE; NET_RemoveFromPacketList(pPacket); NET_TransferRawData(&in_message, pPacket->pPacketData, pPacket->nSize); Q_memcpy(&in_from, &pPacket->net_from_, sizeof(in_from)); if (pPacket->pPacketData) free(pPacket->pPacketData); Mem_Free(pPacket); return TRUE; }
void SV_NewChaseDir2(edict_t *actor, vec3_t destination, float dist) { float deltax, deltay; float tempdir, olddir, turnaround; vec3_t d; olddir = anglemod(((int)(actor->v.ideal_yaw / 45.0)) * 45.0); //So, we're shaving down some of the precision. Ohkay. turnaround = anglemod(olddir - 180); deltax = destination[0] - actor->v.origin[0]; deltay = destination[1] - actor->v.origin[1]; if(deltax > 10) { d[1]= 0; } else if(deltax < -10) { d[1]= 180; } else { d[1] = -1; } //DI_NODIR, so in this function, -1 is a reserved 'null' like value. if(deltay < -10) { d[2] = 270; } else if(deltay > 10) { d[2] = 90; } else { d[2] = -1; } // try direct route if(d[1] != -1 && d[2] != -1) { if(d[1] == 0) { if(d[2] == 90) { tempdir = 45; } else { tempdir = 315; } } else { if(d[2] == 90) { tempdir = 135; } else { tempdir = 215; } } if(tempdir != turnaround && SV_StepDirection(actor, tempdir, dist) != 0) { return; } } // try other directions if(RandomLong(0, 1) != 0 || fabs(deltay) > fabs(deltax)) { //These were originally cast as int before compared. I cannot think of any compelling reason to do so. tempdir = d[1]; d[1] = d[2]; d[2] = tempdir; } if(d[1] != -1 && d[1] != turnaround && SV_StepDirection(actor, d[1], dist) != 0) { return; } if(d[2] != -1 && d[2] != turnaround && SV_StepDirection(actor, d[2], dist) != 0) { return; } /* there is no direct path to the player, so pick another direction */ if(olddir != -1 && SV_StepDirection(actor, olddir, dist) != 0) { return; } //Fine, just run somewhere. if(RandomLong(0, 1) != 0) { for(tempdir = 0; tempdir <= 315; tempdir += 45) { if(tempdir != turnaround && SV_StepDirection(actor, tempdir, dist) != 0) { return; } } } else { for(tempdir = 315; tempdir >= 0; tempdir -= 45) { if(tempdir != turnaround && SV_StepDirection(actor, tempdir, dist) != 0) { return; } } } //We tried. Run backwards. THAT ought to work... if(turnaround != -1 && SV_StepDirection(actor, turnaround, dist) != 0) { return; } //Well, we're stuck somehow. actor->v.ideal_yaw = olddir; // if a bridge was pulled out from underneath a monster, it may not have // a valid standing position at all. if(SV_CheckBottom(actor) == 0) { SV_FixCheckBottom(actor); } }
void PF_WaterMove(edict_t * ent) { double var_10; int var_4_flags; int var_8_waterlevel; int var_c_watertype; // double var_14; //some sort of damage counter, but it keeps not being used... if(ent->v.movetype == MOVETYPE_NOCLIP) { ent->v.air_finished = 12 + global_sv.time0c; return; } if(ent->v.health <= 0) { return; } if(ent->v.deadflag == 0) { var_10 = 3; } else { var_10 = 1; } var_4_flags = ent->v.flags; var_8_waterlevel = ent->v.waterlevel; var_c_watertype = ent->v.watertype; //This area is almost but not quite entirely unlike the drowning code in the SDK. if((var_4_flags & (FL_IMMUNE_WATER | FL_GODMODE)) == 0) { //Gods don't drown, unless they're Bruce Willis if(((var_4_flags & FL_SWIM) && var_8_waterlevel > var_10) || var_8_waterlevel <= var_10) { if(ent->v.air_finished > global_sv.time0c && ent->v.pain_finished > global_sv.time0c) { ent->v.dmg += 2; if(ent->v.dmg < 15) { ent->v.dmg = 10; //wha? } //var_14 = ent->v.dmg; ent->v.pain_finished = 1 + global_sv.time0c; } } else { // if(ent->v.air_finished <= global_sv.time0c) { // if(ent->v.air_finished <= 0 + global_sv.time0c) { } // } ent->v.air_finished = 12 + global_sv.time0c; ent->v.dmg = 2; } } //This is asmess if(var_8_waterlevel == 0) { if((var_4_flags & FL_INWATER) != 0) { //Leave the water. switch(RandomLong(0, 3)) { case 0: SV_StartSound(0, ent, 4, "player/pl_wade1.wav", 255, 0.8, 0, 100); break; case 1: SV_StartSound(0, ent, 4, "player/pl_wade2.wav", 255, 0.8, 0, 100); break; case 2: SV_StartSound(0, ent, 4, "player/pl_wade3.wav", 255, 0.8, 0, 100); break; case 3: SV_StartSound(0, ent, 4, "player/pl_wade4.wav", 255, 0.8, 0, 100); break; } ent->v.flags = var_4_flags & ~FL_INWATER; } ent->v.air_finished = 12 + global_sv.time0c; return; } if(var_c_watertype == Q1CONTENTS_LAVA) { //aah, it stings and burns if(((var_4_flags & (FL_IMMUNE_LAVA | FL_GODMODE)) == 0) && ent->v.dmgtime < global_sv.time0c) { if(ent->v.radsuit_finished < global_sv.time0c) { ent->v.dmgtime = global_sv.time0c + 0.2; } else { ent->v.dmgtime = global_sv.time0c + 1.0; } // var_14 = var_8_waterlevel * 10; } } else if(var_c_watertype == Q1CONTENTS_SLIME) { if(((var_4_flags & (FL_IMMUNE_SLIME | FL_GODMODE)) == 0) && ent->v.dmgtime < global_sv.time0c && ent->v.radsuit_finished < global_sv.time0c) { ent->v.dmgtime = global_sv.time0c + 1.0; // var_14 = var_8_waterlevel * 4; } } if((var_4_flags & FL_INWATER) == 0) { if(var_c_watertype == Q1CONTENTS_WATER) { switch(RandomLong(0, 3)) { case 0: SV_StartSound(0, ent, 4, "player/pl_wade1.wav", 255, 0.8, 0, 100); break; case 1: SV_StartSound(0, ent, 4, "player/pl_wade2.wav", 255, 0.8, 0, 100); break; case 2: SV_StartSound(0, ent, 4, "player/pl_wade3.wav", 255, 0.8, 0, 100); break; case 3: SV_StartSound(0, ent, 4, "player/pl_wade4.wav", 255, 0.8, 0, 100); break; } } ent->v.flags = var_4_flags | FL_INWATER; ent->v.dmgtime = 0; } if((var_4_flags & FL_WATERJUMP) == 0) { VectorMA(ent->v.velocity, (ent->v.waterlevel * -0.8 * host_frametime), ent->v.velocity, ent->v.velocity); } }
static WORD PAL_BattleUIPickAutoMagic( WORD wPlayerRole, WORD wRandomRange ) /*++ Purpose: Pick a magic for the specified player for automatic usage. Parameters: [IN] wPlayerRole - the player role ID. [IN] wRandomRange - the range of the magic power. Return value: The object ID of the selected magic. 0 for physical attack. --*/ { WORD wMagic = 0, w, wMagicNum; int i, iMaxPower = 0, iPower; if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSilence] != 0) { return 0; } for (i = 0; i < MAX_PLAYER_MAGICS; i++) { w = gpGlobals->g.PlayerRoles.rgwMagic[i][wPlayerRole]; if (w == 0) { continue; } wMagicNum = gpGlobals->g.rgObject[w].magic.wMagicNumber; // // skip if the magic is an ultimate move or not enough MP // if (gpGlobals->g.lprgMagic[wMagicNum].wCostMP == 1 || gpGlobals->g.lprgMagic[wMagicNum].wCostMP > gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole] || (SHORT)(gpGlobals->g.lprgMagic[wMagicNum].wBaseDamage) <= 0) { continue; } iPower = (SHORT)(gpGlobals->g.lprgMagic[wMagicNum].wBaseDamage) + RandomLong(0, wRandomRange); if (iPower > iMaxPower) { iMaxPower = iPower; wMagic = w; } } return wMagic; }
// Not best algorithm for linear congruential generators long Random::RandLong( long Low, long High ) { return RandomLong( ) % ( High - Low + 1 ) + Low; }
double Random::RandomReal( ) { return RandomLong( ) / 2147483647.0; }
VOID PAL_BattleStartFrame( VOID ) /*++ Purpose: Called once per video frame in battle. Parameters: None. Return value: None. --*/ { int i; int iMax; BOOL fEnded; WORD wPlayerRole; WORD wDexterity; FLOAT flMax; PAL_BattleUpdateFighters(); // // Update the scene // PAL_BattleMakeScene(); SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL); // // Check if the battle is over // fEnded = TRUE; for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { if (g_Battle.rgEnemy[i].wObjectID != 0) { fEnded = FALSE; break; } } if (fEnded) { // // All enemies are cleared. Won the battle. // g_Battle.BattleResult = kBattleResultWon; SOUND_Play(-1); return; } else { fEnded = TRUE; for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { wPlayerRole = gpGlobals->rgParty[i].wPlayerRole; if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] != 0 || gpGlobals->rgPlayerStatus[wPlayerRole][kStatusPuppet] != 0) { fEnded = FALSE; break; } } if (fEnded) { // // All players are dead. Lost the battle. // g_Battle.BattleResult = kBattleResultLost; return; } } // // Run the logic for all enemies // for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { if (g_Battle.rgEnemy[i].wObjectID == 0) { continue; } if (g_Battle.rgEnemy[i].fTurnStart) { g_Battle.rgEnemy[i].wScriptOnTurnStart = PAL_RunTriggerScript(g_Battle.rgEnemy[i].wScriptOnTurnStart, i); g_Battle.rgEnemy[i].fTurnStart = FALSE; } } for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { if (g_Battle.rgEnemy[i].wObjectID == 0) { continue; } switch (g_Battle.rgEnemy[i].state) { case kFighterWait: flMax = PAL_GetTimeChargingSpeed(PAL_GetEnemyDexterity(i)); if (flMax != 0) { g_Battle.rgEnemy[i].flTimeMeter += flMax; if (g_Battle.rgEnemy[i].flTimeMeter > 100 && flMax > 0) { g_Battle.rgEnemy[i].state = kFighterCom; } } break; case kFighterCom: g_Battle.rgEnemy[i].wScriptOnReady = PAL_RunTriggerScript(g_Battle.rgEnemy[i].wScriptOnReady, i); g_Battle.rgEnemy[i].state = kFighterAct; break; case kFighterAct: ////TEST/////////////////////////////////////////////////////////// SOUND_Play(g_Battle.rgEnemy[i].e.wAttackSound); if (g_Battle.rgEnemy[i].fFirstMoveDone) PAL_BattleUIShowText(va("enemy %d attack (2nd)",i), 500); else PAL_BattleUIShowText(va("enemy %d attack",i), 500); g_Battle.rgEnemy[i].flTimeMeter =0; g_Battle.rgEnemy[i].state = kFighterWait; //////////////////////////////////////////////////////////////////// if (!g_Battle.rgEnemy[i].fFirstMoveDone) { if (g_Battle.rgEnemy[i].e.wDualMove >= 2 || (g_Battle.rgEnemy[i].e.wDualMove != 0 && RandomLong(0, 1))) { g_Battle.rgEnemy[i].flTimeMeter = 100; g_Battle.rgEnemy[i].state = kFighterWait; g_Battle.rgEnemy[i].fFirstMoveDone = TRUE; break; } } g_Battle.rgEnemy[i].fFirstMoveDone = FALSE; g_Battle.rgEnemy[i].fTurnStart = TRUE; break; } } // // Update the battle UI // PAL_BattleUIUpdate(); // // Run the logic for all players // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { wPlayerRole = gpGlobals->rgParty[i].wPlayerRole; // // Skip dead players // if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0 && gpGlobals->rgPlayerStatus[wPlayerRole][kStatusPuppet] == 0) { g_Battle.rgPlayer[i].state = kFighterWait; g_Battle.rgPlayer[i].flTimeMeter = 0; continue; } switch (g_Battle.rgPlayer[i].state) { case kFighterWait: wDexterity = PAL_GetPlayerActualDexterity(wPlayerRole); g_Battle.rgPlayer[i].flTimeMeter += PAL_GetTimeChargingSpeed(wDexterity) * g_Battle.rgPlayer[i].flTimeSpeedModifier; break; case kFighterCom: if (g_Battle.UI.state == kBattleUIWait) { PAL_BattleUIPlayerReady(i); } break; case kFighterAct: wDexterity = PAL_GetPlayerActualDexterity(wPlayerRole); g_Battle.rgPlayer[i].action.flRemainingTime -= PAL_GetTimeChargingSpeed(wDexterity); if (g_Battle.rgPlayer[i].action.flRemainingTime < 0) { // // Perform the action for this player. // PAL_BattlePlayerPerformAction(i); // // Reduce the time for other players when uses coopmagic // if (g_Battle.rgPlayer[i].action.ActionType == kBattleActionCoopMagic) { for (iMax = 0; iMax <= gpGlobals->wMaxPartyMemberIndex; iMax++) { g_Battle.rgPlayer[iMax].flTimeMeter = 0; g_Battle.rgPlayer[iMax].flTimeSpeedModifier = 2.0f; } } else { g_Battle.rgPlayer[i].flTimeMeter = 0; } // // Revert this player back to waiting state. // g_Battle.rgPlayer[i].state = kFighterWait; g_Battle.rgPlayer[i].flTimeSpeedModifier = 1.0f; } break; } } // // Start the UI for the fastest and ready player // flMax = 0; iMax = 0; for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { if (g_Battle.rgPlayer[i].state == kFighterCom || (g_Battle.rgPlayer[i].state == kFighterAct && g_Battle.rgPlayer[i].action.ActionType == kBattleActionCoopMagic)) { flMax = 0; break; } else if (g_Battle.rgPlayer[i].state == kFighterWait) { if (g_Battle.rgPlayer[i].flTimeMeter > flMax) { iMax = i; flMax = g_Battle.rgPlayer[i].flTimeMeter; } } } if (flMax > 100.0f) { g_Battle.rgPlayer[iMax].state = kFighterCom; g_Battle.rgPlayer[iMax].fDefending = FALSE; } ////TEST/////////////////////////////////////////////////////////-START if (g_InputState.dwKeyPress & kKeyFlee){ for (i = 0; i < 5; i++){ gpGlobals->g.PlayerRoles.rgwHP[i] = 0; } return; } ////TEST/////////////////////////////////////////////////////////-END }
// Generate a chat message from a specified message type, and return // the pointer of the generated message char *CChatManager::GenerateChat(CBaseBot *pClient, const char *type) { static char msg[256]; // for the chat message msg[0] = '\0'; // initialize the string unsigned short usCrc = CRC_Block((unsigned char *)type, strlen(type)); // find if we already have this section int found; for (found = 0; found < m_ChatItem.size(); found++) { if (m_ChatItem[found].type == usCrc) break; } if (found < m_ChatItem.size()) { char sz[256]; strncpy(sz, m_ChatItem[found].PickMessage(), 256); int length = strlen(sz); char *p = sz; while (p != NULL && *p) { if (*p == '%') { char type = *(++p); // skip to next character to get the type int hiscore = -9999, j, count; CClient *pPickedClient = NULL; char buffer[32]; switch (type) { case '%': strncat(msg, "%", 256); break; case 'n': // bot name strncpy(buffer, pClient->GetNetName(), 32); HumanizeName(buffer); strncat(msg, buffer, 256); // append it to the message break; case 'r': // random opponent j = RandomLong(0, g_pServer->GetMaxClients()); for (count = 0; count < g_pServer->GetMaxClients(); count++, j++) { CClient *p = g_pServer->m_rgpClients[j]; if (p != pClient && p->IsValid()) { strncpy(buffer, p->GetNetName(), 32); HumanizeName(buffer); strncat(msg, buffer, 256); // append it to the message break; } } if (count >= g_pServer->GetMaxClients()) return NULL; // can't find any player, don't say anything break; case 'f': // opponent in first place for (j = 0; j < g_pServer->GetMaxClients(); j++) { CClient *p = g_pServer->m_rgpClients[j]; if (p == pClient || !p->IsValid()) continue; if (p->GetFrags() >= hiscore) { hiscore = p->GetFrags(); pPickedClient = p; } } if (pPickedClient) { strncpy(buffer, pPickedClient->GetNetName(), 32); HumanizeName(buffer); // humanize the name strncat(msg, buffer, 256); // append it to the message } else { return NULL; // can't find such a player, don't say anything } break; case 'l': // opponent in last place hiscore = 9999; for (j = 0; j < g_pServer->GetMaxClients(); j++) { CClient *p = g_pServer->m_rgpClients[j]; if (p == pClient || !p->IsValid()) continue; if (p->GetFrags() <= hiscore) { hiscore = p->GetFrags(); pPickedClient = p; } } if (pPickedClient) { strncpy(buffer, pPickedClient->GetNetName(), 32); HumanizeName(buffer); // humanize the name strncat(msg, buffer, 256); // append it to the message } else { return NULL; // can't find such a player, don't say anything } break; case 'm': // map title strncat(msg, g_pServer->GetMapName(), 256); // get the map name break; case 'v': // last victim of this bot if (pClient->Chat()->m_strLastVictim.length() <= 0) return NULL; // we don't have a victim yet, don't say anything strncat(msg, pClient->Chat()->m_strLastVictim.c_str(), 256); break; case 'k': // last player killed this bot if (pClient->Chat()->m_strLastKiller.length() <= 0) return NULL; // this bot hasn't been killed yet, don't say anything strncat(msg, pClient->Chat()->m_strLastKiller.c_str(), 256); break; } p++; // skip to the next character continue; } char *prev = p; p = strchr(p, '%'); // search for the next "%" sign if (p) { *p = '\0'; // if found, terminate the string } strncat(msg, prev, 256); // append the remaining text if (p) { *p = '%'; // restore the '%' } } HumanizeChat(msg); // 'Humanize' the chat message return msg; } return NULL; // not found }
// choose a weapon to buy and returns the weapon ID // emotion: 0 (defensive) - 100 (aggressive) // type: 0 - primary, 1 - secondary int CCSBuyManager::ChooseWeapon(int iEmotion, int iMoney, int iTeam, int iType) { int iPersonality = 1; // personality: 0 - defensive, 1 - normal, 2 - aggressive CServerCS *pServerCS = dynamic_cast<CServerCS *>(g_pServer); int iRandom = RandomLong(0, 100); // choose a random value int delta = iRandom - iEmotion; if (abs(delta) > 33) { if (delta > 0) { iPersonality = 0; // defensive } else { iPersonality = 2; // aggressive } } std::vector<int> &p = personalized; if (m_fBuyPersonalized) { p = personalized; m_fBuyPersonalized = false; } else if (iTeam == CS_TEAM_TERRORIST) { if (iPersonality == 0) p = defensive_t; else if (iPersonality == 1) p = normal_t; else p = aggressive_t; } else { if (iPersonality == 0) p = defensive_ct; else if (iPersonality == 1) p = normal_ct; else p = aggressive_ct; } int iSize = p.size(); std::vector<int> chosen; // weapons which has been chosen int iCount = 0, i, j; for (i = 0; i < iSize; i++) { int iId = p[i]; iCount++; // see if this weapon can be bought // if we're NOT using CS 1.6 and this weapon is only for CS 1.6 if (pServerCS->GetCSVersion() == CS_VERSION_WON && (iId == CS_WEAPON_GALIL || iId == CS_WEAPON_FAMAS || iId == CS_WEAPON_SHIELDGUN)) continue; // skip this weapon // are we on an assasssination map? if (pServerCS->GetMapType() & MAP_AS) { // skip certain weapons which is not available on as_* maps if (iTeam == CS_TEAM_TERRORIST) { if (iId == CS_WEAPON_M3 || iId == CS_WEAPON_XM1014 || iId == CS_WEAPON_MP5NAVY || iId == CS_WEAPON_P90 || iId == CS_WEAPON_M249) continue; // skip this weapon } else { if (iId == CS_WEAPON_AWP) continue; // skip this weapon } } cs_weapontable_s *pWeapon = get_weapon(iId); if (!pWeapon) // check if this weapon is in our list continue; // skip this weapon if not // check if we have enough money (also add some money for ammo) if (iMoney < pWeapon->iPrice + 150) continue; // skip this weapon if not if ((iType == 1 && (UtilCS::WeaponIsPrimary(iId) || iId == CS_WEAPON_SHIELDGUN)) || (iType == 0 && UtilCS::WeaponIsPistol(iId))) continue; // skip this weapon // this is a good weapon, add it to our chosen list for (j = 0; j < iCount; j++) { // add multiple instances of the weapon depends on number of weapon skipped // so that better weapons have more possibility to get chosen chosen.push_back(iId); } iCount = 0; } if (chosen.empty()) return 0; // no weapon is chosen, can't buy weapon // select the weapon to buy in the table float flFactor = (iMoney - 3000.0) / (16000 - 3000) * 3; if (flFactor < 1) flFactor = 1; // 1) better weapons has more chances to get chosen // 2) be even more aggressive if we're rich float f = log10(RandomFloat(1, pow(10, flFactor))); return chosen[(int)((float)(chosen.size() - 1) * f / flFactor + 0.5)]; }
/*++ Generate the battle scene into the scene buffer. --*/ VOID PAL_BattleMakeScene(void) { int i; PAL_POS pos; LPBYTE pSrc, pDst; BYTE b; // // Draw the background // pSrc = g_Battle.lpBackground->pixels; pDst = g_Battle.lpSceneBuf->pixels; for (i = 0; i < g_Battle.lpSceneBuf->pitch * g_Battle.lpSceneBuf->h; i++) { b = (*pSrc & 0x0F); b += g_Battle.sBackgroundColorShift; if (b & 0x80) { b = 0; } else if (b & 0x70) { b = 0x0F; } *pDst = (b | (*pSrc & 0xF0)); ++pSrc; ++pDst; } PAL_ApplyWave(g_Battle.lpSceneBuf); // // Draw the enemies // for (i = g_Battle.wMaxEnemyIndex; i >= 0; i--) { pos = g_Battle.rgEnemy[i].pos; if (g_Battle.rgEnemy[i].rgwStatus[kStatusConfused] > 0 && g_Battle.rgEnemy[i].rgwStatus[kStatusSleep] == 0 && g_Battle.rgEnemy[i].rgwStatus[kStatusParalyzed] == 0) { // // Enemy is confused // pos = PAL_XY(PAL_X(pos) + RandomLong(-1, 1), PAL_Y(pos)); } pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame))); if (g_Battle.rgEnemy[i].wObjectID != 0) { if (g_Battle.rgEnemy[i].iColorShift) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgEnemy[i].iColorShift); } else { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); } } } if (g_Battle.lpSummonSprite != NULL) { // // Draw the summoned god // pos = PAL_XY(PAL_X(g_Battle.posSummon) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame)) / 2, PAL_Y(g_Battle.posSummon) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame))); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame), g_Battle.lpSceneBuf, pos); } else { // // Draw the players // for (i = gpGlobals->wMaxPartyMemberIndex; i >= 0; i--) { pos = g_Battle.rgPlayer[i].pos; if (gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusConfused] != 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusSleep] == 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusParalyzed] == 0 && gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] > 0) { // // Player is confused // continue; } pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame))); if (g_Battle.rgPlayer[i].iColorShift != 0) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgPlayer[i].iColorShift); } else if (g_Battle.iHidingTime == 0) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); } } // // Confused players should be drawn on top of normal players // for (i = gpGlobals->wMaxPartyMemberIndex; i >= 0; i--) { if (gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusConfused] != 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusSleep] == 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusParalyzed] == 0 && gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] > 0) { // // Player is confused // pos = PAL_XY(PAL_X(g_Battle.rgPlayer[i].pos), PAL_Y(g_Battle.rgPlayer[i].pos) + RandomLong(-1, 1)); pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame))); if (g_Battle.rgPlayer[i].iColorShift != 0) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgPlayer[i].iColorShift); } else if (g_Battle.iHidingTime == 0) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); } } } } }
//----------------------------------------------------------------------------- // Purpose: Creates a target address, for sending messages to reliably //----------------------------------------------------------------------------- int CTrackerNET::FindTarget(CNetAddress &address, int targetID, int sequenceNumber) { bool createNew = true; NetworkTarget_t *target = NULL; int listIndex = 0; // find the address in the map int targetIndex = FindTargetIndexByAddress(address); if (m_TargetMap.IsValidIndex(targetIndex)) { listIndex = m_TargetMap[targetIndex].targetIndex; target = &(m_TargetList[listIndex]); // make sure the targetID's match, otherwise the connection has been invalidated if (targetID == -1 || target->targetID == targetID) { return listIndex; } else { if (sequenceNumber == 1) { //!! reset the connection WriteToLog("-> Connection Reset (%d) (%d, %d)\n", sequenceNumber, targetID, target->targetID); } else { WriteToLog("-> Connection Restart (%d) (%d, %d)\n", sequenceNumber, targetID, target->targetID); } createNew = false; } } if (createNew) { // add a new connection to the end of the list listIndex = m_TargetList.AddToTail(); target = &(m_TargetList[listIndex]); target->needAck = false; // add the target to the map TargetMapItem_t newItem; newItem.targetIndex = listIndex; newItem.netAddress = address; m_TargetMap.Insert(newItem); // ensure that it's the first one in the sequence if (sequenceNumber > 1) { WriteToLog("-> Contacted by unknown old connection (targetID:%d)\n", targetID); } } // append to the end of the list target->netAddress = address; // initialize sequence numbers target->outgoingSequence = 1; target->outgoingAcknowledged = 0; target->incomingSequence = 0; target->incomingAcknowledged = 0; if (sequenceNumber != -1) { // this is the first packet we've received, but from and old connection; so jump the correct sequence number target->incomingSequence = sequenceNumber - 1; } // target->createTime = m_pThreads->GetTime(); if (targetID >= 0) { target->targetID = targetID; } else { target->targetID = RandomLong(1, MAX_RANDOM_RANGE); } if (createNew && targetID >= 0) { WriteToLog("Creating new target ID (%d)\n", target->targetID); } else { WriteToLog("Establishing connection to target ID (%d)\n", target->targetID); } return listIndex; }
VOID PAL_BattleMakeScene( VOID ) /*++ Purpose: Generate the battle scene into the scene buffer. Parameters: None. Return value: None. --*/ { int i; PAL_POS pos; LPBYTE pSrc, pDst; //BYTE b; // // Draw the background // pSrc = g_Battle.lpBackground->pixels; pDst = g_Battle.lpSceneBuf->pixels; // optimized by ZBY ZBY_TIMING_BEGIN(2); make_colorshift_table(g_Battle.sBackgroundColorShift); if (0) { //if (g_Battle.sBackgroundColorShift == 0) { memcpy(pDst, pSrc, g_Battle.lpSceneBuf->pitch * g_Battle.lpSceneBuf->h); } else { i = g_Battle.lpSceneBuf->pitch * g_Battle.lpSceneBuf->h; while (i--) { /*b = (*pSrc & 0x0F); b += g_Battle.sBackgroundColorShift; if (b & 0x80) { b = 0; } else if (b & 0x70) { b = 0x0F; } *pDst = (b | (*pSrc & 0xF0)); assert(*pDst == cs_table[*pSrc]); */ *pDst = cs_table[*pSrc]; ++pSrc; ++pDst; } } ZBY_TIMING_END(2, "PAL_BattleMakeScene"); PAL_ApplyWave(g_Battle.lpSceneBuf); // // Draw the enemies // for (i = g_Battle.wMaxEnemyIndex; i >= 0; i--) { pos = g_Battle.rgEnemy[i].pos; if (g_Battle.rgEnemy[i].rgwStatus[kStatusConfused] > 0 && g_Battle.rgEnemy[i].rgwStatus[kStatusSleep] == 0 && g_Battle.rgEnemy[i].rgwStatus[kStatusParalyzed] == 0) { // // Enemy is confused // pos = PAL_XY(PAL_X(pos) + RandomLong(-1, 1), PAL_Y(pos)); } pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame))); if (g_Battle.rgEnemy[i].wObjectID != 0) { if (g_Battle.rgEnemy[i].iColorShift) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgEnemy[i].iColorShift); } else { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); } } } if (g_Battle.lpSummonSprite != NULL) { // // Draw the summoned god // pos = PAL_XY(PAL_X(g_Battle.posSummon) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame)) / 2, PAL_Y(g_Battle.posSummon) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame))); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame), g_Battle.lpSceneBuf, pos); } else { // // Draw the players // for (i = gpGlobals->wMaxPartyMemberIndex; i >= 0; i--) { pos = g_Battle.rgPlayer[i].pos; if (gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusConfused] != 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusSleep] == 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusParalyzed] == 0 && gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] > 0) { // // Player is confused // continue; } pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame))); if (g_Battle.rgPlayer[i].iColorShift != 0) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgPlayer[i].iColorShift); } else if (g_Battle.iHidingTime == 0) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); } } // // Confused players should be drawn on top of normal players // for (i = gpGlobals->wMaxPartyMemberIndex; i >= 0; i--) { if (gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusConfused] != 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusSleep] == 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusParalyzed] == 0 && gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] > 0) { // // Player is confused // pos = PAL_XY(PAL_X(g_Battle.rgPlayer[i].pos), PAL_Y(g_Battle.rgPlayer[i].pos) + RandomLong(-1, 1)); pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame))); if (g_Battle.rgPlayer[i].iColorShift != 0) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgPlayer[i].iColorShift); } else if (g_Battle.iHidingTime == 0) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); } } } } }
// Generate a reply message from the input message, and return the // pointer of the reply message char *CChatManager::GenerateReply(CBaseBot *pClient, CClient *pFrom, const char *msg) { static char message[256]; // for the reply message message[0] = '\0'; // initialize the string char *p; int i; // find a reply block with the correct keyword for (i = 0; i < m_ChatReply.size(); i++) { if (m_ChatReply[i].IsValidReply(msg)) break; } if (i >= m_ChatReply.size()) { // no replies for this sentence are found if (RandomLong(1, 100) > 50) { // about half the time use a general reply if ((p = GenerateChat(pClient, "GENERAL_REPLIES")) != NULL) { strncpy(message, p, 256); } else { return NULL; // No general replies } } else { return NULL; // don't reply to this message } } else { // we have replies for this sentence, generate the message now p = (char *)m_ChatReply[i].PickMessage(); if (!p) { return NULL; // no message is available, don't proceed } while (p && *p) { if (*p == '%') { char type = *(++p); // skip to next character to get the type int hiscore = -9999, j, count; CClient *pPickedClient = NULL; char buffer[32]; switch (type) { case '%': strncat(message, "%", 256); break; case 'n': // bot name strncpy(buffer, pClient->GetNetName(), 32); HumanizeName(buffer); strncat(message, buffer, 256); // append it to the message break; case 'r': // random opponent j = RandomLong(0, g_pServer->GetMaxClients()); for (count = 0; count < g_pServer->GetMaxClients(); count++, j++) { CClient *p = g_pServer->m_rgpClients[j]; if (p != pClient && p->IsValid()) { strncpy(buffer, p->GetNetName(), 32); HumanizeName(buffer); strncat(message, buffer, 256); // append it to the message break; } } if (count >= g_pServer->GetMaxClients()) return NULL; // can't find any player, don't say anything break; case 'f': // opponent in first place for (j = 0; j < g_pServer->GetMaxClients(); j++) { CClient *p = g_pServer->m_rgpClients[j]; if (p == pClient || !p->IsValid()) continue; if (p->GetFrags() >= hiscore) { hiscore = p->GetFrags(); pPickedClient = p; } } if (pPickedClient) { strncpy(buffer, pPickedClient->GetNetName(), 32); HumanizeName(buffer); // humanize the name strncat(message, buffer, 256); // append it to the message } else { return NULL; // can't find such a player, don't say anything } break; case 'l': // opponent in last place hiscore = 9999; for (j = 0; j < g_pServer->GetMaxClients(); j++) { CClient *p = g_pServer->m_rgpClients[j]; if (p == pClient || !p->IsValid()) continue; if (p->GetFrags() <= hiscore) { hiscore = p->GetFrags(); pPickedClient = p; } } if (pPickedClient) { strncpy(buffer, pPickedClient->GetNetName(), 32); HumanizeName(buffer); // humanize the name strncat(message, buffer, 256); // append it to the message } else { return NULL; // can't find such a player, don't say anything } break; case 'v': // last victim of this bot if (pClient->Chat()->m_strLastVictim.length() <= 0) return NULL; // we don't have a victim yet strncat(message, pClient->Chat()->m_strLastVictim.c_str(), 256); break; case 'k': // last player killed this bot if (pClient->Chat()->m_strLastKiller.length() <= 0) return NULL; // this bot hasn't been killed yet strncat(message, pClient->Chat()->m_strLastKiller.c_str(), 256); break; case 'm': // map title strncat(message, g_pServer->GetMapName(), 256); // get the map name break; // reply specific items case 's': // player to reply strncat(message, pFrom->GetNetName(), 256); break; } p++; // skip to the next character continue; } char *prev = p; p = strchr(p, '%'); // search for the next "%" sign if (p) { *p = '\0'; // if found, terminate the string } strncat(message, prev, 256); // append the remaining text if (p) { *p = '%'; // restore the '%' } } HumanizeChat(message); // 'humanize' the chat message } return message; // return the message }
VOID PAL_PlayerLevelUp( WORD wPlayerRole, WORD wNumLevel ) /*++ Purpose: Increase the player's level by wLevels. Parameters: [IN] wPlayerRole - player role ID. [IN] wNumLevel - number of levels to be increased. Return value: None. --*/ { WORD i; // // Add the level // gpGlobals->g.PlayerRoles.rgwLevel[wPlayerRole] += wNumLevel; if (gpGlobals->g.PlayerRoles.rgwLevel[wPlayerRole] > MAX_LEVELS) { gpGlobals->g.PlayerRoles.rgwLevel[wPlayerRole] = MAX_LEVELS; } for (i = 0; i < wNumLevel; i++) { // // Increase player's stats // gpGlobals->g.PlayerRoles.rgwMaxHP[wPlayerRole] += 10 + RandomLong(0, 8); gpGlobals->g.PlayerRoles.rgwMaxMP[wPlayerRole] += 8 + RandomLong(0, 6); gpGlobals->g.PlayerRoles.rgwAttackStrength[wPlayerRole] += 4 + RandomLong(0, 1); gpGlobals->g.PlayerRoles.rgwMagicStrength[wPlayerRole] += 4 + RandomLong(0, 1); gpGlobals->g.PlayerRoles.rgwDefense[wPlayerRole] += 2 + RandomLong(0, 1); gpGlobals->g.PlayerRoles.rgwDexterity[wPlayerRole] += 2 + RandomLong(0, 1); gpGlobals->g.PlayerRoles.rgwFleeRate[wPlayerRole] += 2; } #define STAT_LIMIT(t) { if ((t) > 999) (t) = 999; } STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwMaxHP[wPlayerRole]); STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwMaxMP[wPlayerRole]); STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwAttackStrength[wPlayerRole]); STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwMagicStrength[wPlayerRole]); STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwDefense[wPlayerRole]); STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwDexterity[wPlayerRole]); STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwFleeRate[wPlayerRole]); #undef STAT_LIMIT // // Reset experience points to zero // gpGlobals->Exp.rgPrimaryExp[wPlayerRole].wExp = 0; gpGlobals->Exp.rgPrimaryExp[wPlayerRole].wLevel = gpGlobals->g.PlayerRoles.rgwLevel[wPlayerRole]; }
VOID PAL_BattlePlayerPerformAction( WORD wPlayerIndex ) /*++ Purpose: Perform the selected action for a player. Parameters: [IN] wPlayerIndex - the index of the player. Return value: None. --*/ { // TODO SHORT sDamage; WORD wPlayerRole = gpGlobals->rgParty[wPlayerIndex].wPlayerRole; SHORT sTarget = g_Battle.rgPlayer[wPlayerIndex].action.sTarget; int x, y; int i, t; WORD str, def, res, wObject; BOOL fCritical, fPoisoned; PAL_BattlePlayerValidateAction(wPlayerIndex); PAL_BattleBackupStat(); switch (g_Battle.rgPlayer[wPlayerIndex].action.ActionType) { case kBattleActionAttack: if (sTarget != -1) { // // Attack one enemy // if (g_Battle.rgEnemy[sTarget].wObjectID == 0) { sTarget = PAL_BattleSelectAutoTarget(); g_Battle.rgPlayer[wPlayerIndex].action.sTarget = sTarget; } for (t = 0; t < (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusDualAttack] ? 2 : 1); t++) { str = PAL_GetPlayerAttackStrength(wPlayerRole); def = g_Battle.rgEnemy[sTarget].e.wDefense; def += (g_Battle.rgEnemy[sTarget].e.wLevel + 6) * 4; res = g_Battle.rgEnemy[sTarget].e.wAttackResistance; fCritical = FALSE; sDamage = PAL_CalcPhysicalAttackDamage(str, def, res); if (RandomLong(0, 5) == 0) { // // Critical Hit // sDamage *= 3; fCritical = TRUE; } if (wPlayerRole == 0 && RandomLong(0, 11) == 0) { // // Bonus hit for Li Xiaoyao // sDamage *= 2; fCritical = TRUE; } if (sDamage <= 0) { sDamage = 1; } if (g_Battle.rgEnemy[sTarget].e.wHealth > (WORD)sDamage) { g_Battle.rgEnemy[sTarget].e.wHealth -= sDamage; } else { g_Battle.rgEnemy[sTarget].e.wHealth = 0; } if (t == 0) { g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 7; PAL_BattleDelay(4, 0); } PAL_BattleShowPlayerAttackAnim(wPlayerIndex, fCritical); // // Show the number of damage // x = PAL_X(g_Battle.rgEnemy[sTarget].pos); y = PAL_Y(g_Battle.rgEnemy[sTarget].pos) - 70; x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[sTarget].lpSprite, g_Battle.rgEnemy[sTarget].wCurrentFrame)) / 2; y += PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[sTarget].lpSprite, g_Battle.rgEnemy[sTarget].wCurrentFrame)) / 2; if (y < 10) { y = 10; } PAL_BattleUIShowNum((WORD)sDamage, PAL_XY(x, y), kNumColorBlue); } } else { // // Attack all enemies // for (t = 0; t < (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusDualAttack] ? 2 : 1); t++) { int division = 1; const int index[MAX_ENEMIES_IN_TEAM] = {2, 1, 0, 4, 3}; fCritical = (RandomLong(0, 5) == 0); if (t == 0) { g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 7; PAL_BattleDelay(4, 0); } PAL_BattleShowPlayerAttackAnim(wPlayerIndex, fCritical); for (i = 0; i < MAX_ENEMIES_IN_TEAM; i++) { if (g_Battle.rgEnemy[index[i]].wObjectID == 0 || index[i] > g_Battle.wMaxEnemyIndex) { continue; } str = PAL_GetPlayerAttackStrength(wPlayerRole); def = g_Battle.rgEnemy[index[i]].e.wDefense; def += (g_Battle.rgEnemy[index[i]].e.wLevel + 6) * 4; res = g_Battle.rgEnemy[index[i]].e.wAttackResistance; sDamage = PAL_CalcPhysicalAttackDamage(str, def, res); if (fCritical) { // // Critical Hit // sDamage *= 3; } sDamage /= division; if (sDamage <= 0) { sDamage = 1; } if (g_Battle.rgEnemy[index[i]].e.wHealth > (WORD)sDamage) { g_Battle.rgEnemy[index[i]].e.wHealth -= sDamage; } else { g_Battle.rgEnemy[index[i]].e.wHealth = 0; } // // Show the number of damage // x = PAL_X(g_Battle.rgEnemy[index[i]].pos); y = PAL_Y(g_Battle.rgEnemy[index[i]].pos) - 70; x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[index[i]].lpSprite, g_Battle.rgEnemy[index[i]].wCurrentFrame)) / 2; y += PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[index[i]].lpSprite, g_Battle.rgEnemy[index[i]].wCurrentFrame)) / 2; if (y < 10) { y = 10; } PAL_BattleUIShowNum((WORD)sDamage, PAL_XY(x, y), kNumColorBlue); division++; if (division > 3) { division = 3; } } } } PAL_BattleUpdateFighters(); PAL_BattleMakeScene(); PAL_BattleDelay(5, 0); break; case kBattleActionAttackMate: break; case kBattleActionCoopMagic: break; case kBattleActionDefend: g_Battle.rgPlayer[wPlayerIndex].fDefending = TRUE; break; case kBattleActionFlee: break; case kBattleActionMagic: break; case kBattleActionThrowItem: break; case kBattleActionUseItem: wObject = g_Battle.rgPlayer[wPlayerIndex].action.wActionID; PAL_BattleShowPlayerUseItemAnim(wPlayerIndex, wObject, sTarget); // // Run the script // gpGlobals->g.rgObject[wObject].item.wScriptOnUse = PAL_RunTriggerScript(gpGlobals->g.rgObject[wObject].item.wScriptOnUse, (sTarget == -1) ? 0xFFFF : gpGlobals->rgParty[sTarget].wPlayerRole); // // Remove the item if the item is consuming and the script succeeded // if ((gpGlobals->g.rgObject[wObject].item.wFlags & kItemFlagConsuming) && g_fScriptSuccess) { PAL_AddItemToInventory(wObject, -1); } PAL_BattleUpdateFighters(); PAL_BattleDisplayStatChange(); PAL_BattleDelay(8, 0); break; case kBattleActionPass: break; } PAL_BattlePostActionCheck(FALSE); // // Check for poisons // fPoisoned = FALSE; PAL_BattleBackupStat(); for (i = 0; i < MAX_POISONS; i++) { wObject = gpGlobals->rgPoisonStatus[i][wPlayerIndex].wPoisonID; if (wObject != 0) { fPoisoned = TRUE; gpGlobals->rgPoisonStatus[i][wPlayerIndex].wPoisonScript = PAL_RunTriggerScript(gpGlobals->rgPoisonStatus[i][wPlayerIndex].wPoisonScript, wPlayerRole); } } if (fPoisoned) { PAL_BattleDelay(3, 0); PAL_BattleUpdateFighters(); if (PAL_BattleDisplayStatChange()) { PAL_BattleDelay(12, 0); } } // // Update statuses // for (i = 0; i < kStatusAll; i++) { if (gpGlobals->rgPlayerStatus[wPlayerRole][i] > 0) { gpGlobals->rgPlayerStatus[wPlayerRole][i]--; } } }
// We only like to become the declarer when: // 1) We have 3 or more beating cards (2's or Joker's) // 2) We have 6 or more high-ranked cards (K/A/2/Joker) // 3) We have 2 or less leftover cards which cannot be easily got rid of // (single cards smaller than J or pairs smaller than 8) // TODO: may be much smarter than this... int CBot::Bid(int iAtLeast) { UTIL_Delay(RandomLong(800, 1500)); // delay a while int iValue = 0, i, j, k, num_cards[16], iNumLeftOver = 0; int iNumTriple = 0, iNumHead = 0, subseq = -1, last_subseq = -1; // count all kind of cards memset(num_cards, 0, sizeof(num_cards)); for (i = 0; i < m_iNumHandCard; i++) { num_cards[m_rgHandCard[i].GetValue() - 3]++; } if (num_cards[10] + num_cards[11] + num_cards[13] + num_cards[14] + num_cards[15] < 6) { // we have too few big cards, not feeling so good iValue = RandomLong(0, 1); goto end; } // take out all sequences for (i = 0; i < 8; i++) { if (num_cards[i] == 0) { continue; } for (j = i + 1; j < 12; j++) { if (num_cards[j] <= 0) { // the sequence ends right here break; } } if (j - i < 5) { i = j - 1; continue; // contains less than 5 cards, ignore this } if (num_cards[j - 1] >= 3 && j - i > 5) { j--; // do not end with a bomb or a triple } if (num_cards[i] >= 3 && j - i > 5) { i++; // do not start with a bomb or a triple } // take the sequence out for (k = i; k < j; k++) { num_cards[k]--; // take out one card from this rank } // see if we have some subsequences which can be included // in the main sequence to form 2 or more sequences... if (j - i < 7) { continue; // less than 7 cards is impossible } last_subseq = i; for (k = i; k < j; k++) { if (num_cards[k] > 0) { if (subseq == -1) { subseq = k; } } else { if (subseq != -1) { if (j - subseq >= 5 && k - last_subseq >= 5) { // take this out as well while (subseq < k) { assert(num_cards[subseq] > 0); num_cards[subseq++]--; } last_subseq = subseq; } subseq = -1; } } } i = j - 1; // skip the cards we have already proceeded } // take out all double sequences for (i = 0; i < 10; i++) { if (num_cards[i] < 2) { continue; } for (j = i + 1; j < 12; j++) { if (num_cards[j] < 2) { // the sequence ends right here break; } } if (j - i < 3) { i = j - 1; continue; // contains less than 5 cards, ignore this } if (num_cards[j - 1] >= 3 && j - i > 3) { j--; // do not end with a bomb or a triple } if (num_cards[i] >= 3 && j - i > 3) { i++; // do not start with a bomb or a triple } // take the sequence out for (k = i; k < j; k++) { num_cards[k] -= 2; // take out 2 cards from this rank } } // leftovers // pairs smaller than 8 for (i = 0; i < 5; i++) { if (num_cards[i] == 2) { iNumLeftOver++; } } // singles smaller than J for (i = 0; i < 8; i++) { if (num_cards[i] == 1) { iNumLeftOver++; } } // triples and quads for (i = 0; i < 12; i++) { if (num_cards[i] == 3) { iNumTriple++; } else if (num_cards[i] == 4) { iNumHead++; // bomb } } // big cards iNumHead += num_cards[13]; // 2 iNumHead += num_cards[14]; // Black Joker iNumHead += num_cards[15]; // Red Joker if (iNumHead < 3) { iValue = RandomLong(0, 1); goto end; // not feeling so good } if (!num_cards[15]) { iNumHead--; } if (!num_cards[14]) { iNumHead--; } i = iNumLeftOver - iNumTriple - iNumHead; #ifdef BOT_DEBUG printf("CBot::Bid(): iNumLeftOver = %d, iNumTriple = %d, iNumHead =%d -> %d\n", iNumLeftOver, iNumTriple, iNumHead, i); #endif if (i > 3) { iValue = RandomLong(0, 2); // we're not feeling so good } else if (i >= 2) { iValue = RandomLong(2, 3); // try a bet } else { iValue = 3; // very good } end: return (iValue < iAtLeast) ? 0 : iValue; }
// returns true if buying is completed, false if not bool CBotCS::BuyStuff() { int iId; CServerCS *pServerCS = dynamic_cast<CServerCS *>(g_pServer); switch (m_iBuyCount) { case 0: // if bot is rich, buy armor+helmet; else buy armor if (m_iAccount > RandomLong(3000, 5000)) { DebugMsg(DEBUG_BOTAI, "CBotCS::BuyStuff(): buying armor + helmet"); g_General.FakeClientCommand(this, "buy;menuselect 8;menuselect 2"); } else { DebugMsg(DEBUG_BOTAI, "CBotCS::BuyStuff(): buying armor"); g_General.FakeClientCommand(this, "buy;menuselect 8;menuselect 1"); } break; case 1: // if bot doesn't have a primary weapon, buy one if (HasPrimary() || HasShield()) { DebugMsg(DEBUG_BOTAI, "CBotCS::BuyStuff(): already have a primary weapon; exiting"); break; // don't proceed if we already have one } // TODO: emotion // select a primary weapon iId = g_pBuyMgrCS->ChooseWeapon(RandomLong(0, 100)/*FIXME*/, m_iAccount, GetTeam()); if (iId != 0) { DebugMsg(DEBUG_BOTAI, "CBotCS::BuyStuff(): Buying weapon: %s", g_General.GetWeaponName(iId)); cs_weapontable_s *pWeapon = get_weapon(iId); assert(pWeapon); if (pServerCS->GetCSVersion() == CS_VERSION_STEAM) g_General.FakeClientCommand(this, pWeapon->szBuyCmd16); else g_General.FakeClientCommand(this, pWeapon->szBuyCmd15); } else { DebugMsg(DEBUG_BOTAI, "CBotCS::BuyStuff(): no primary weapon is selected"); } break; case 2: // if bot doesn't have a secondary weapon, buy one if (GetWeapons() & ((1 << CS_WEAPON_P228) | (1 << CS_WEAPON_DEAGLE) | (1 << CS_WEAPON_FIVESEVEN) | (1 << CS_WEAPON_ELITE))) { DebugMsg(DEBUG_BOTAI, "CBotCS::BuyStuff(): already have a secondary weapon; exiting"); break; // don't proceed if we already have a good secondary weapon } // TODO: emotion // select a primary weapon iId = g_pBuyMgrCS->ChooseWeapon(RandomLong(0, 100)/*FIXME*/, m_iAccount, GetTeam(), 1); if (iId != 0) { DebugMsg(DEBUG_BOTAI, "CBotCS::BuyStuff(): Buying weapon: %s", g_General.GetWeaponName(iId)); if (HasShield() && iId == CS_WEAPON_ELITE) break; // if we have a shield, we can't buy the dual elites cs_weapontable_s *pWeapon = get_weapon(iId); assert(pWeapon); if (pServerCS->GetCSVersion() == CS_VERSION_STEAM) g_General.FakeClientCommand(this, pWeapon->szBuyCmd16); else g_General.FakeClientCommand(this, pWeapon->szBuyCmd15); } else { DebugMsg(DEBUG_BOTAI, "CBotCS::BuyStuff(): no secondary weapon is selected"); } break; case 3: // buy enough ammo DebugMsg(DEBUG_BOTAI, "CBotCS::BuyStuff(): buying ammo"); g_General.FakeClientCommand(this, "buy;menuselect 6"); // prim. ammo g_General.FakeClientCommand(this, "buy;menuselect 7"); // sec. ammo break; case 4: // buy grenades, defusers, etc. // if bot is CT, randomly buy the defuser if (GetTeam() == CS_TEAM_CT && RandomLong(1, 100) < 33 && m_iAccount > 200) { DebugMsg(DEBUG_BOTAI, "CBotCS::BuyStuff(): buying defuser"); if (pServerCS->GetCSVersion() == CS_VERSION_STEAM) g_General.FakeClientCommand(this, "defuser"); // use alias in CS 1.6 else g_General.FakeClientCommand(this, "buyequip;menuselect 6"); } if (RandomLong(1, 100) < 75 && m_iAccount >= 300 && !(GetWeapons() & CS_WEAPON_HEGRENADE)) { DebugMsg(DEBUG_BOTAI, "CBotCS::BuyStuff(): buying HE Grenade"); // Buy a HE Grenade g_General.FakeClientCommand(this, "buyequip"); g_General.FakeClientCommand(this, "menuselect 4"); } if (RandomLong(1, 100) < 50 && m_iAccount >= 200 && !(GetWeapons() & CS_WEAPON_FLASHBANG)) { DebugMsg(DEBUG_BOTAI, "CBotCS::BuyStuff(): buying Concussion Grenade"); // Buy a Concussion Grenade, i.e., 'FlashBang' g_General.FakeClientCommand(this, "buyequip"); g_General.FakeClientCommand(this, "menuselect 3"); } if (RandomLong(1, 100) < 30 && m_iAccount >= 300 && !(GetWeapons() & CS_WEAPON_SMOKEGRENADE)) { DebugMsg(DEBUG_BOTAI, "CBotCS::BuyStuff(): buying Smoke Grenade"); // Buy a Smoke Grenade g_General.FakeClientCommand(this, "buyequip"); g_General.FakeClientCommand(this, "menuselect 5"); } break; case 5: // buying finished return true; // no more buying break; default: CGeneral::TerminateOnError("CBotCS::BuyStuff(): m_iBuyCount error"); break; } m_iBuyCount++; // add the buying counter return false; }