Files
assaultcube-/source/src/serveractions.h
T
Rafael Barreto ae71b35a27 i do not believe i am committing this same fix again
git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@5506 e016b1c5-ed68-44aa-a2f7-31cac88cffde
2010-07-31 02:20:57 +00:00

331 lines
10 KiB
C

// available server actions
enum { EE_LOCAL_SERV = 1, EE_DED_SERV = 1<<1 }; // execution environment
int roleconf(int key)
{ // current defaults: "fGkBMasRCDEW"
if(strchr(scl.voteperm, tolower(key))) return CR_DEFAULT;
if(strchr(scl.voteperm, toupper(key))) return CR_ADMIN;
return (key) == tolower(key) ? CR_DEFAULT : CR_ADMIN;
}
struct serveraction
{
int role; // required client role
int area; // only on ded servers
string desc;
virtual void perform() = 0;
virtual bool isvalid() { return true; }
virtual bool isdisabled() { return false; }
serveraction() : role(CR_DEFAULT), area(EE_DED_SERV) { desc[0] = '\0'; }
virtual ~serveraction() { }
};
void kick_abuser(int cn, int &cmillis, int &count, int limit)
{
if ( cmillis + 30000 > servmillis ) count++;
else {
count -= count > 0 ? (servmillis - cmillis)/30000 : 0;
if ( count <= 0 ) count = 1;
}
cmillis = servmillis;
if( count >= limit ) disconnect_client(cn, DISC_ABUSE);
}
bool mapisok(mapstats *ms)
{
if ( ms->hasflags ) // Check if flags are ok
{
struct { short x, y; } fl[2];
loopi(2)
{
if(ms->flags[i] == 1)
{
short *fe = ms->entposs + ms->flagents[i] * 3;
fl[i].x = *fe; fe++; fl[i].y = *fe;
}
else fl[i].x = fl[i].y = 0; // the map has no valid flags
}
FlagFlag = pow2(fl[0].x - fl[1].x) + pow2(fl[0].y - fl[1].y);
}
else FlagFlag = MINFF * 1000; // the map has no flags
return Mheight < MAXMHEIGHT && (Mopen = checkarea(testlayout_factor, testlayout)) < MAXMAREA && FlagFlag > MINFF;
}
struct mapaction : serveraction
{
char *map;
int mode;
bool mapok, queue;
void perform()
{
if (queue) return;
if(isdedicated && numclients() > 2 && smode >= 0 && smode != 1 && gamemillis > gamelimit/4)
{
forceintermission = true;
nextgamemode = mode;
copystring(nextmapname, map);
}
else
{
startgame(map, mode);
}
}
bool isvalid() { return serveraction::isvalid() && mode != GMODE_DEMO && map[0] && mapok && !(isdedicated && !m_mp(mode)); }
bool isdisabled() { return maprot.current() && !maprot.current()->vote; }
mapaction(char *map, int mode, int caller, bool q) : map(map), mode(mode), queue(q)
{
if(isdedicated)
{
bool notify = valid_client(caller);
int maploc = MAP_NOTFOUND;
mapstats *ms = map[0] ? getservermapstats(map, false, &maploc) : NULL;
mapok = ms != NULL && ( (mode != GMODE_COOPEDIT && mapisok(ms)) || (mode == GMODE_COOPEDIT && !readonlymap(maploc)) );
if(!mapok)
{
defformatstring(msg)("%s", ms ? ( readonlymap(maploc) ? "this map cannot be coopedited in this server" : "sorry, but this map does not satisfy some quality requisites to be played in MultiPlayer Mode" ) : "the server does not have this map" );
if(notify) sendservmsg(msg, caller);
}
else
{ // check, if map supports mode
if(mode == GMODE_COOPEDIT && !strchr(scl.voteperm, 'e')) role = CR_ADMIN;
bool romap = mode == GMODE_COOPEDIT && readonlymap(maploc);
int smode = mode; // 'borrow' the mode macros by replacing a global by a local var
bool spawns = mode == GMODE_COOPEDIT || (m_teammode && !m_ktf ? ms->hasteamspawns : ms->hasffaspawns);
bool flags = mode != GMODE_COOPEDIT && m_flags && !m_htf ? ms->hasflags : true;
if(!spawns || !flags || romap)
{ // unsupported mode
if(strchr(scl.voteperm, 'P')) role = CR_ADMIN;
else if(!strchr(scl.voteperm, 'p')) mapok = false; // default: no one can vote for unsupported mode/map combinations
defformatstring(msg)("\f3map \"%s\" does not support \"%s\": ", behindpath(map), modestr(mode, false));
if(romap) concatstring(msg, "map is readonly");
else
{
if(!spawns) concatstring(msg, "player spawns");
if(!spawns && !flags) concatstring(msg, " and ");
if(!flags) concatstring(msg, "flag bases");
concatstring(msg, " missing");
}
if(notify) sendservmsg(msg, caller);
logline(ACLOG_INFO, "%s", msg);
}
}
loopv(scl.adminonlymaps)
{
const char *s = scl.adminonlymaps[i], *h = strchr(s, '#'), *m = behindpath(map);
size_t sl = strlen(s);
if(h && h != s)
{
sl = h - s;
if(mode != atoi(h + 1)) continue;
}
if(sl == strlen(m) && !strncmp(m, scl.adminonlymaps[i], sl)) role = CR_ADMIN;
}
}
else mapok = true;
area |= EE_LOCAL_SERV; // local too
formatstring(desc)("load map '%s' in mode '%s'", map, modestr(mode));
}
~mapaction() { DELETEA(map); }
};
struct demoplayaction : serveraction
{
char *demofilename;
void perform() { startdemoplayback(demofilename); }
demoplayaction(char *demofilename) : demofilename(demofilename)
{
area = EE_LOCAL_SERV; // only local
}
~demoplayaction() { DELETEA(demofilename); }
};
struct playeraction : serveraction
{
int cn;
ENetAddress address;
void disconnect(int reason)
{
int i = findcnbyaddress(&address);
if(i >= 0) disconnect_client(i, reason);
}
virtual bool isvalid() { return valid_client(cn) && clients[cn]->role != CR_ADMIN; } // actions can't be done on admins
playeraction(int cn) : cn(cn)
{
if(isvalid()) address = clients[cn]->peer->address;
};
};
struct forceteamaction : playeraction
{
void perform() { updateclientteam(cn, team_opposite(clients[cn]->team), FTR_SILENTFORCE); }
virtual bool isvalid() { return m_teammode && valid_client(cn); }
forceteamaction(int cn, int caller) : playeraction(cn)
{
if(cn != caller) role = roleconf('f');
if(isvalid() && !(clients[cn]->state.forced && clients[caller]->role != CR_ADMIN)) formatstring(desc)("force player %s to the enemy team", clients[cn]->name);
}
};
struct giveadminaction : playeraction
{
void perform() { changeclientrole(cn, CR_ADMIN, NULL, true); }
giveadminaction(int cn) : playeraction(cn)
{
role = CR_ADMIN;
// role = roleconf('G');
}
};
struct kickaction : playeraction
{
bool wasvalid;
void perform() { disconnect(DISC_MKICK); }
virtual bool isvalid() { return wasvalid || playeraction::isvalid(); }
kickaction(int cn, char *reason) : playeraction(cn)
{
wasvalid = false;
role = roleconf('k');
if(isvalid() && strlen(reason) > 3)
{
wasvalid = true;
formatstring(desc)("kick player %s, reason: %s", clients[cn]->name, reason);
}
}
};
struct banaction : playeraction
{
bool wasvalid;
void perform()
{
ban b = { address, servmillis+20*60*1000 };
bans.add(b);
disconnect(DISC_MBAN);
}
virtual bool isvalid() { return wasvalid || playeraction::isvalid(); }
banaction(int cn, char *reason) : playeraction(cn)
{
wasvalid = false;
role = roleconf('B');
if(isvalid() && strlen(reason) > 3)
{
wasvalid = true;
formatstring(desc)("ban player %s, reason: %s", clients[cn]->name, reason);
}
}
};
struct removebansaction : serveraction
{
void perform() { bans.shrink(0); }
removebansaction()
{
role = roleconf('B');
copystring(desc, "remove all bans");
}
};
struct mastermodeaction : serveraction
{
int mode;
void perform() { changemastermode(mode); }
bool isvalid() { return mode >= 0 && mode < MM_NUM; }
mastermodeaction(int mode) : mode(mode)
{
role = roleconf('M');
if(isvalid()) formatstring(desc)("change mastermode to '%s'", mmfullname(mode));
}
};
struct enableaction : serveraction
{
bool enable;
enableaction(bool enable) : enable(enable) {}
};
struct autoteamaction : enableaction
{
void perform()
{
autoteam = enable;
sendservermode();
if(m_teammode && enable) refillteams(true);
}
autoteamaction(bool enable) : enableaction(enable)
{
role = roleconf('A');
if(isvalid()) formatstring(desc)("%s autoteam", enable ? "enable" : "disable");
}
};
struct shuffleteamaction : serveraction
{
void perform()
{
sendf(-1, 1, "ri2", SV_SERVERMODE, sendservermode(false) | AT_SHUFFLE);
shuffleteams();
}
bool isvalid() { return serveraction::isvalid() && m_teammode; }
shuffleteamaction()
{
role = roleconf('S');
if(isvalid()) copystring(desc, "shuffle teams");
}
};
struct recorddemoaction : enableaction // TODO: remove completely
{
void perform() { }
bool isvalid() { return serveraction::isvalid(); }
recorddemoaction(bool enable) : enableaction(enable)
{
role = roleconf('R');
if(isvalid()) formatstring(desc)("%s demorecord", enable ? "enable" : "disable");
}
};
struct stopdemoaction : serveraction
{
bool isvalid() { return serveraction::isvalid() && m_demo; }
void perform()
{
if(m_demo) enddemoplayback();
}
stopdemoaction()
{
role = CR_ADMIN;
area |= EE_LOCAL_SERV;
copystring(desc, "stop demo playback");
}
};
struct cleardemosaction : serveraction
{
int demo;
void perform() { cleardemos(demo); }
cleardemosaction(int demo) : demo(demo)
{
role = roleconf('C');
if(isvalid()) formatstring(desc)("clear demo %d", demo);
}
};
struct serverdescaction : serveraction
{
char *sdesc;
int cn;
ENetAddress address;
void perform() { updatesdesc(sdesc, &address); }
bool isvalid() { return serveraction::isvalid() && updatedescallowed() && valid_client(cn); }
serverdescaction(char *sdesc, int cn) : sdesc(sdesc), cn(cn)
{
role = roleconf('D');
formatstring(desc)("set server description to '%s'", sdesc);
if(isvalid()) address = clients[cn]->peer->address;
}
~serverdescaction() { DELETEA(sdesc); }
};