local void Cformula(const char *cmd, const char *params, Player *p, const Target *target) { if (params && *params) { char var_name_buf[MAX_VAR_NAME_LENGTH]; char error_buf[200]; error_buf[0] = '\0'; // parse the formula Formula *f = formula->ParseFormula(params, error_buf, sizeof(error_buf)); if (f) { if (allow_var_creation(p)) { PData *pdata = PPDATA(p, pdata_key); double value = formula->EvaluateFormula(f, pdata->vars, var_name_buf, error_buf, sizeof(error_buf)); formula->FreeFormula(f); if (error_buf[0] == '\0') { chat->SendMessage(p, "%s = %lf", var_name_buf, value); // chat->SendMessage(p, "You have too many variables. Free some with ?unset"); } else { chat->SendMessage(p, "Evaluation Error: %s", error_buf); } } else { PData *pdata = PPDATA(p, pdata_key); double value = formula->EvaluateFormula(f, pdata->vars, NULL, error_buf, sizeof(error_buf)); formula->FreeFormula(f); if (error_buf[0] == '\0') { chat->SendMessage(p, "You have too many variables. Free some with ?unset"); chat->SendMessage(p, "%lf", value); } else { chat->SendMessage(p, "Evaluation Error: %s", error_buf); } } } else { chat->SendMessage(p, "Parse Error: %s", error_buf); } } else { chat->SendMessage(p, "You must enter a formula to evaluate."); } }
local int HigherThan(Player *a, Player *b) { char cap[MAXGROUPLEN+16]; const char *bgrp = ((pdata*)PPDATA(b, pdkey))->group; snprintf(cap, sizeof(cap), "higher_than_%s", bgrp); return HasCapability(a, cap); }
local void check_and_send_banner(Player *p, int callothers, int from_player) { bdata *bd = PPDATA(p, bdkey); if (bd->status == 0) return; else if (bd->status == 1) { if (CheckBanner(p)) bd->status = 2; else if (lm) lm->LogP(L_DRIVEL, "banners", p, "denied permission to use a banner"); } if (bd->status == 2) { /* send to everyone */ struct S2CBanner pkt = { S2C_BANNER, p->pid }; memcpy(&pkt.banner, &bd->banner, sizeof(pkt.banner)); if (!p->arena) return; net->SendToArena(p->arena, NULL, (byte*)&pkt, sizeof(pkt), NET_RELIABLE | NET_PRI_N1); /* notify other modules */ if (callothers) DO_CBS(CB_SET_BANNER, p->arena, SetBannerFunc, (p, &bd->banner, from_player)); } }
/* After 20 seconds have passed */ local int TimeUp(void *p) { Player *host = p; Arena *arena = host->arena; Adata *adata = P_ARENA_DATA(arena, arenaKey); if (adata->started == 0) return 0; /* Open the Doors and prize the players */ Player *g; Link *link; cs->ArenaOverride(arena, ok_Doors, 0); pd->Lock(); FOR_EACH_PLAYER(g) { if (g->arena == arena) { cs->SendClientSettings(g); if (g->p_ship != SHIP_SPEC) { Target target; target.type = T_PLAYER; target.u.p = g; game->ShipReset(&target); game->GivePrize(&target, PRIZE_ROCKET, 1); if (adata->mystery) { game->GivePrize(&target, PRIZE_CLOAK, 1); game->GivePrize(&target, PRIZE_STEALTH, 1); } Pdata *pdata = PPDATA(g, playerKey); pdata->won = 0; } } } pd->Unlock(); CheckLegalShip(arena); chat->SendArenaSoundMessage(arena, 104, "Race started."); adata->starttime = current_millis(); adata->started = 2; mm->RegCallback(CB_PLAYERACTION, PlayerAction, arena); mm->RegCallback(CB_SHIPFREQCHANGE, ShipFreqChange, arena); mm->RegCallback(CB_REGION, EnterRegion, arena); ml->SetTimer(RocketArea, 200, 200, host, arena); return 0; }
local void RemoveGroup(Player *p, const char *info) { pdata *pdata = PPDATA(p, pdkey); if (!p->arena) return; /* in all cases, set current group to default */ astrncpy(pdata->group, DEFAULT, MAXGROUPLEN); switch (pdata->source) { case src_default: /* player is in the default group already, nothing to do */ break; case src_global: cfg->SetStr(staff_conf, AG_GLOBAL, p->name, DEFAULT, info, TRUE); break; case src_arena: cfg->SetStr(staff_conf, p->arena->basename, p->name, DEFAULT, info, TRUE); break; #ifdef CFG_USE_ARENA_STAFF_LIST case src_arenalist: cfg->SetStr(p->arena->cfg, "Staff", p->name, DEFAULT, info); break; #endif case src_temp: break; } }
local void Cvars(const char *cmd, const char *params, Player *p, const Target *target) { PData *pdata = PPDATA(p, pdata_key); LinkedList list; LLInit(&list); HashEnum(pdata->vars, enum_vars, &list); if (LLGetHead(&list) != NULL) { Link *link; StringBuffer sb; SBInit(&sb); chat->SendMessage(p, "Variables:"); for (link = LLGetHead(&list); link; link = link->next) { SBPrintf(&sb, ", %s", (const char*)link->data); } chat->SendWrappedText(p, SBText(&sb, 2)); SBDestroy(&sb); LLEmpty(&list); } else { chat->SendMessage(p, "No Variables."); } }
local void Cunset(const char *cmd, const char *params, Player *p, const Target *target) { if (params && *params) { PData *pdata = PPDATA(p, pdata_key); FormulaVariable *var; if (*params == '$') { // ignore a leading $ params++; } var = HashGetOne(pdata->vars, params); if (var) { HashRemove(pdata->vars, params, var); afree(var); chat->SendMessage(p, "Unset %s", params); } else { chat->SendMessage(p, "No such variable '%s'", params); } } else { chat->SendMessage(p, "Usage: ?unset <var>"); } }
local int Decrypt(Player *p, byte *data, int len) { EncData *ed, **p_ed = PPDATA(p, enckey); pthread_mutex_lock(&mtx); ed = *p_ed; pthread_mutex_unlock(&mtx); return ed ? do_dec(ed, data, len) : len; }
/* Set data->shipchanges to 0 when player enters the arena. */ local void PlayerAction(Arena *arena, Player *p, int action) { if (action == PA_ENTERARENA) { Pdata *data = PPDATA(p, playerKey); data->shipchanges = 0; } }
local void ship_change_cb(Player *p, int newship, int oldship, int newfreq, int oldfreq) { pdata *data = PPDATA(p, pdkey); if (newship != oldship && newship != SHIP_SPEC) { data->last_change = current_ticks(); } }
local void SetTempGroup(Player *p, const char *newgroup) { pdata *pdata = PPDATA(p, pdkey); if (newgroup) { astrncpy(pdata->group, newgroup, MAXGROUPLEN); pdata->source = src_temp; } }
/* Set data->played if the player has changed ships. */ local void ShipFreqChange(Player *p, int newship, int oldship, int newfreq, int oldfreq) { Pdata *data = PPDATA(p, playerKey); data->shipchanges++; if (p->p_ship != SHIP_SPEC) { data->played = 1; } }
local void Void(Player *p) { EncData *ed, **p_ed = PPDATA(p, enckey); pthread_mutex_lock(&mtx); ed = *p_ed; afree(ed); *p_ed = NULL; pthread_mutex_unlock(&mtx); }
local void Init(Player *p, int k) { EncData *ed, **p_ed = PPDATA(p, enckey); pthread_mutex_lock(&mtx); if (!(ed = *p_ed)) ed = *p_ed = amalloc(sizeof(*ed)); pthread_mutex_unlock(&mtx); do_init(ed, k); }
local void paction(Player *p, int action, Arena *arena) { pdata *pdata = PPDATA(p, pdkey); if (action == PA_PREENTERARENA) update_group(p, pdata, arena, TRUE); else if (action == PA_CONNECT) update_group(p, pdata, NULL, TRUE); else if (action == PA_DISCONNECT || action == PA_LEAVEARENA) astrncpy(pdata->group, "none", MAXGROUPLEN); }
local int allow_var_creation(Player *p) { PData *pdata = PPDATA(p, pdata_key); int count = count_vars(pdata->vars); /* cfghelp: Formula:MaxVariables, global, int, def: 10, mod: formula_cmd * How many variables a player can set with ?formula. */ int max_count = cfg->GetInt(GLOBAL, "Fomula", "MaxVariables", 10); return count < max_count; }
local int CanChangeToShip(Player *p, int new_ship, int is_changing, char *err_buf, int buf_len) { pdata *data = PPDATA(p, pdkey); int shipchangeinterval, antiwarp_non_flagger, antiwarp_flagger; /* cfghelp: Misc:ShipChangeInterval, arena, int, def: 500 * The allowable interval between player ship changes, in ticks. */ shipchangeinterval = cfg->GetInt(p->arena->cfg, "Misc", "ShipChangeInterval", 500); /* cfghelp: Misc:AntiwarpShipChange, arena, int, def, 0 * prevents players without flags from changing ships * while antiwarped. */ antiwarp_non_flagger = cfg->GetInt(p->arena->cfg, "Misc", "AntiwarpShipChange", 0); /* cfghelp: Misc:AntiwarpFlagShipChange, arena, int, def, 0 * prevents players with flags from changing ships * while antiwarped. */ antiwarp_flagger = cfg->GetInt(p->arena->cfg, "Misc", "AntiwarpFlagShipChange", 0); if (shipchangeinterval > 0 && data->last_change + shipchangeinterval > current_ticks()) { if (err_buf) snprintf(err_buf, buf_len, "You've changed ships too recently. Please wait."); return 0; } if (p->p_ship != SHIP_SPEC && (antiwarp_non_flagger || antiwarp_flagger) && game->IsAntiwarped(p, NULL)) { int flags; if (flagcore) { flags = flagcore->CountPlayerFlags(p); } else { flags = 0; } if ((flags && antiwarp_flagger) || (!flags && antiwarp_non_flagger)) { if (err_buf) snprintf(err_buf, buf_len, "You are antiwarped!"); return 0; } } return 1; }
local void init_players() { Player *p; Link *link; pd->Lock(); FOR_EACH_PLAYER(p) { PData *pdata = PPDATA(p, pdata_key); pdata->vars = HashAlloc(); } pd->Unlock(); }
local void free_players() { Player *p; Link *link; pd->Lock(); FOR_EACH_PLAYER(p) { PData *pdata = PPDATA(p, pdata_key); if (pdata->vars) { HashEnum(pdata->vars, hash_enum_afree, NULL); HashFree(pdata->vars); } } pd->Unlock(); }
local void SetBanner(Player *p, Banner *bnr) { bdata *bd = PPDATA(p, bdkey); LOCK(); bd->banner = *bnr; bd->status = 1; /* if he's not in the playing state yet, just hold the banner and * status at 1. we'll check it when he enters the arena. * if he is playing, though, do the check and send now. */ if (p->status == S_PLAYING) check_and_send_banner(p, TRUE, FALSE); UNLOCK(); }
/* If a player enters the game, make his current frequency his old frequency. */ local void PlayerAction(Player *p, int action, Arena *arena) { MyArenaData *at = P_ARENA_DATA(p->arena, adkey); Pdata *d = PPDATA(p, pdkey); if (at->state == 1 && action == PA_ENTERARENA) { d->oldfreq = p->p_freq; } else { d->oldfreq = p->p_freq; if (at->state != 1) { at->state = 0; } } }
local void SetPermGroup(Player *p, const char *group, int global, const char *info) { pdata *pdata = PPDATA(p, pdkey); /* first set it for the current session */ astrncpy(pdata->group, group, MAXGROUPLEN); /* now set it permanently */ if (global) { cfg->SetStr(staff_conf, AG_GLOBAL, p->name, group, info, TRUE); pdata->source = src_global; } else if (p->arena) { cfg->SetStr(staff_conf, p->arena->basename, p->name, group, info, TRUE); pdata->source = src_arena; } }
local void player_action(Player *p, int action, Arena *arena) { PData *pdata = PPDATA(p, pdata_key); if (action == PA_CONNECT) { FormulaVariable *var = amalloc(sizeof(FormulaVariable)); var->name = astrdup("me"); var->type = VAR_TYPE_PLAYER; var->p = p; pdata->vars = HashAlloc(); HashAdd(pdata->vars, var->name, var); } else if (action == PA_DISCONNECT) { HashEnum(pdata->vars, var_free_enum, NULL); HashFree(pdata->vars); } }
/* Check the jackpot, check the flags, and lock/unlock the teams. */ local void LockCheck(Arena *a, Player *p, int freq, int *points) { jackpot = jp->GetJP(a); lockjackpot = cfg->GetInt(a->cfg, "Lockjackpot", "Minimum", 10000000); MyArenaData *at = P_ARENA_DATA(a, adkey); if (jackpot > lockjackpot) { Target target; target.type = T_ARENA; target.u.arena = a; int freqflags = flagcore->CountFreqFlags(p->arena, p->p_freq); if (at->state == 0) { if (freqflags > 24) { obj->Toggle(&target, 321, 1); // chat->SendArenaMessage(a, "Teams have been locked!"); at->state = 1; Arena *arena; Player *g; Link *link; pd->Lock(); FOR_EACH_PLAYER(g) { if (g->arena == arena) { Pdata *d = PPDATA(g, pdkey); d->oldfreq = g->p_freq; } } pd->Unlock(); return; } }
/* Store the player's score into the database */ local void SetScore(Player *p, float time) { int ctime = (int)time; //TODO: FIXME //use pdata, store time, and compare db->Query(db_gettop, p, 1, "SELECT * FROM `racestats` WHERE arena=? AND time=(SELECT MIN(time) FROM racestats WHERE arena=?);", p->arena->basename, p->arena->basename); db->Query(NULL,NULL,0,"INSERT INTO `racestats` VALUES(#,?,#,?,NOW());", ctime, p->name, (int)p->p_ship, p->arena->basename); Pdata *pdata = PPDATA(p, playerKey); if (ctime) { if (ctime < pdata->bestime || !pdata->bestime) { pdata->bestime = ctime; Adata *adata = P_ARENA_DATA(p->arena, arenaKey); if (!adata->bestime) { chat->SendArenaSoundMessage(p->arena, 7, "%s sets the bar for this track with %.3f seconds on the clock!", p->name, time / 1000); adata->bestime = ctime; adata->bestship = p->p_ship; //adata->bestname = p->name; //adata->bestdate = "today"; } else if (ctime < adata->bestime) { float diff = adata->bestime - ctime; chat->SendArenaSoundMessage(p->arena, 7, "%s broke the track record by %.3f seconds! Previous record was %.3f seconds (ship %i).", p->name, diff / 1000, (float)adata->bestime / 1000, adata->bestship); //set by %s (%s) in ship %i. adata->bestime = ctime; adata->bestship = p->p_ship; //adata->bestname = p->name; //adata->bestdate = "today"; } } } }
/* Returned result from ?best */ local void db_best(int status, db_res *res, void *clos) { Player *p = (Player*)clos; int results = db->GetRowCount(res); db_row *row; row = db->GetRow(res); //get first if (results < 1) { chat->SendMessage(p, "You've never raced in here."); } else { int seconds = atoi(db->GetField(row, 0)); int ship = atoi(db->GetField(row, 2)) + 1; chat->SendMessage(p, "Your best record: %.3f seconds using ship %i on %s", (float)seconds / 1000, ship, db->GetField(row, 4)); Pdata *pdata = PPDATA(p, playerKey); pdata->bestime = seconds; } }
local void new_player(Player *p, int isnew) { char *group = ((pdata*)PPDATA(p, pdkey))->group; if (isnew) astrncpy(group, "none", MAXGROUPLEN); }
local int HasCapability(Player *p, const char *cap) { const char *group = ((pdata*)PPDATA(p, pdkey))->group; return cfg->GetStr(groupdef, group, cap) != NULL; }
/* List stats. */ local void FlagReset(Arena *arena, int freq, int points, int stat, int interval, Player *p, Target *target) { gametime = current_millis(); if ((gametime - wintime) < 0) wintime = gametime; int ctsecs = (gametime - wintime) / 1000; int ctmins = ctsecs / 60; int chours = ctmins / 60; int csecs = ctsecs - (ctmins * 60); int cmins = ctmins - (chours * 60); Link *link; Player *g; int kills = 0, deaths = 0, tks = 0, fkills = 0, fdeaths = 0, goals = 0, flagdrops = 0, flagtime = 0, shipchanges = 0, killpoints = 0; int reward = jp->GetJP(arena) + 10; chat->SendArenaMessage(arena,"|-------------------------------------------------------------------------------|"); chat->SendArenaMessage(arena,"| Reward: %-12d Game Time: %03i:%02i:%02i |", reward, chours, cmins, csecs); chat->SendArenaMessage(arena,"|-------------------------------------------------------------------------------|"); chat->SendArenaMessage(arena,"| Player W L TK FW FL G FD FT SC KP |"); chat->SendArenaMessage(arena,"|-------------------------------------------------------------------------------|"); pd->Lock(); FOR_EACH_PLAYER(g) { Pdata *data = PPDATA(g, playerKey); /* Only list players who've played. */ if ((data->played == 1 && g->arena == arena) || (g->p_ship != SHIP_SPEC && g->arena == arena)) { kills = stats->GetStat(g, STAT_KILLS, INTERVAL_GAME); deaths = stats->GetStat(g, STAT_DEATHS, INTERVAL_GAME); tks = stats->GetStat(g, STAT_TEAM_KILLS, INTERVAL_GAME); fkills = stats->GetStat(g, STAT_FLAG_KILLS, INTERVAL_GAME); fdeaths = stats->GetStat(g, STAT_FLAG_DEATHS, INTERVAL_GAME); goals = stats->GetStat(g, STAT_BALL_GOALS, INTERVAL_GAME); flagdrops = stats->GetStat(g, STAT_FLAG_DROPS, INTERVAL_GAME); flagtime = stats->GetStat(g, STAT_FLAG_CARRY_TIME, INTERVAL_GAME); shipchanges = data->shipchanges; killpoints = stats->GetStat(g, STAT_KILL_POINTS, INTERVAL_GAME); chat->SendArenaMessage(arena,"| %-24s %-4d %-4d %-4d %-4d %-4d %-3d %-3d %-4d %-3d %-10d |", g->name, kills, deaths, tks, fkills, fdeaths, goals, flagdrops, flagtime, shipchanges, killpoints); } } pd->Unlock(); chat->SendArenaMessage(arena,"|-------------------------------------------------------------------------------|"); wintime = current_millis(); /* Reset Shipchanges and check if they've played (i.e. unspecced) */ pd->Lock(); FOR_EACH_PLAYER(g) { Pdata *data = PPDATA(g, playerKey); data->shipchanges = 0; data->played = 0; } pd->Unlock(); }
local const char *GetGroup(Player *p) { return ((pdata*)PPDATA(p, pdkey))->group; }