1 /* bzflag
2 * Copyright (c) 1993-2021 Tim Riker
3 *
4 * This package is free software; you can redistribute it and/or
5 * modify it under the terms of the license found in the file
6 * named COPYING that should have accompanied this file.
7 *
8 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 */
12
13 // TimeLimit.cpp : bzfs plugin to change/set the match duration
14 //
15
16 #include "bzfsAPI.h"
17 #include <sstream>
18 #include <stdio.h>
19 #include <string.h>
20
21 #define MAX_TIMES 20
22
23 class TimeLimit : public bz_Plugin, public bz_CustomSlashCommandHandler
24 {
25 public:
26
Name()27 virtual const char* Name ()
28 {
29 return "Time Limit";
30 }
31 virtual void Init ( const char* config );
32 virtual void Cleanup ();
33 virtual void Event ( bz_EventData *eventData );
34 virtual bool SlashCommand ( int playerID, bz_ApiString, bz_ApiString, bz_APIStringList*);
35
36 protected:
37
38 private:
39
40 };
41
42 BZ_PLUGIN(TimeLimit)
43
44 // variable to save the original -time value
45 float saveTimeLimit = 0;
46
47 // list to hold the available match durations
48 bz_APIStringList* timeList = bz_newStringList();
49
50 // Displays the available match durations
showMatchDurations(int playerID)51 void showMatchDurations(int playerID)
52 {
53 bz_sendTextMessagef (BZ_SERVER, playerID, "Not a valid match duration, valid match durations are : ");
54 for (unsigned i=0; i < timeList->size(); i++)
55 bz_sendTextMessagef (BZ_SERVER, playerID, "* %s minute(s)",timeList->get(i).c_str());
56 }
57
58
59 // Checks if it's a valid match duration or not
isValidTime(float timelimit)60 bool isValidTime ( float timelimit )
61 {
62 if ( timeList->size() == 0 ) return true;
63
64 for (unsigned i=0; i < timeList->size(); i++)
65 {
66 if ( atof(timeList->get(i).c_str()) == timelimit )
67 return true;
68 }
69 return false;
70 }
71
72
Event(bz_EventData * eventData)73 void TimeLimit::Event ( bz_EventData *eventData )
74 {
75 switch (eventData->eventType)
76 {
77 case bz_ePlayerJoinEvent:
78 {
79 // if it's the first player that joins, then reset the time to default
80 if ( bz_getPlayerCount() == 1 && bz_isTimeManualStart() && !bz_isCountDownActive() && !bz_isCountDownInProgress())
81 bz_setTimeLimit(saveTimeLimit);
82 }
83 break;
84
85 //reset the time to default at gameover
86 case bz_eGameEndEvent:
87 {
88 bz_setTimeLimit(saveTimeLimit);
89 }
90 break;
91
92 default:
93 {
94 // do nothing
95 }
96 }
97
98 }
99
100
convertIntToString(const unsigned int integer)101 std::string convertIntToString(const unsigned int integer)
102 {
103 std::ostringstream ostr;
104
105 ostr << integer;
106
107 return ostr.str();
108 }
109
110
parseCommand(const char * commandLine)111 void parseCommand ( const char* commandLine )
112 {
113 const size_t len = strlen(commandLine);
114
115 if (len != 0)
116 {
117 unsigned int range_begin, range_end;
118 char junk;
119
120 if (sscanf(commandLine, "%u-%u%c", &range_begin, &range_end, &junk) == 2)
121 {
122 while (range_begin <= range_end)
123 timeList->push_back(convertIntToString(range_begin++));
124 }
125 else if (strspn(commandLine, ",0123456789") == len)
126 timeList->tokenize(commandLine, ",", MAX_TIMES, false);
127 }
128 }
129
130
SlashCommand(int playerID,bz_ApiString cmd,bz_ApiString,bz_APIStringList * cmdParams)131 bool TimeLimit::SlashCommand ( int playerID, bz_ApiString cmd, bz_ApiString, bz_APIStringList* cmdParams )
132 {
133
134 if (strcasecmp (cmd.c_str(), "timelimit"))
135 return false;
136
137 // Check permissions
138 if (! bz_hasPerm(playerID,"TIMELIMIT"))
139 {
140 bz_sendTextMessagef (BZ_SERVER, playerID, "You do not have permission to run the timelimit command");
141 return true;
142 }
143
144 // If the server is not configured for manual countdown the timelimit
145 // command can't be used
146 if (! bz_isTimeManualStart())
147 {
148 bz_sendTextMessagef (BZ_SERVER, playerID, "This server was not configured for manual clock countdowns");
149 return true;
150 }
151
152 if (cmdParams->get(0).c_str()[0] == '\0')
153 {
154 bz_sendTextMessagef (BZ_SERVER, playerID, "Usage : /timelimit <minutes>|show|reset");
155 return true;
156 }
157
158 // displaying the current timelimit
159 if (strcasecmp(cmdParams->get(0).c_str(),"show") == 0 )
160 {
161 bz_sendTextMessagef (BZ_SERVER, playerID,"Match duration is set to %.0f minute(s)",(bz_getTimeLimit() / 60));
162 return true;
163 }
164
165 // check if there is already a countdown in progress or if a match is
166 // already in progress
167 if ( bz_isCountDownInProgress() )
168 {
169 bz_sendTextMessagef (BZ_SERVER, playerID,
170 "There is a countdown already in progress, match duration can't be changed now");
171 return true;
172 }
173 else if ( bz_isCountDownActive() )
174 {
175 bz_sendTextMessagef (BZ_SERVER, playerID, "A game is already in progress, match duration can't be changed now");
176 return true;
177 }
178
179 bz_BasePlayerRecord *playerRecord;
180 playerRecord = bz_getPlayerByIndex(playerID);
181
182 // resets the timer to the default
183 if (strcasecmp(cmdParams->get(0).c_str(),"reset") == 0 )
184 {
185 bz_setTimeLimit(saveTimeLimit);
186 bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "Match duration reset to %.0f minute(s) by %s",(bz_getTimeLimit() / 60),
187 playerRecord->callsign.c_str());
188 return true;
189 }
190
191 unsigned i, nonumber=0;
192
193 for (i=0; i < strlen(cmdParams->get(0).c_str()); i++)
194 {
195 if (isdigit(cmdParams->get(0).c_str()[i]) == 0) nonumber=1;
196 }
197
198 if (nonumber == 0 )
199 {
200 float limit = (float)atof(cmdParams->get(0).c_str());
201 // Don't allow timelimit being equal or lower then 0
202 if (limit > 0 )
203 {
204
205 if (! isValidTime(limit))
206 {
207
208 showMatchDurations(playerID);
209 return true;
210 }
211
212 bz_setTimeLimit(limit * 60);
213 bz_sendTextMessagef (BZ_SERVER, BZ_ALLUSERS, "Match duration set to %.0f minute(s) by %s",(bz_getTimeLimit() / 60),
214 playerRecord->callsign.c_str());
215 }
216 else
217 {
218 bz_sendTextMessagef (BZ_SERVER, playerID, "Match duration can't be equal or lower then 0");
219 return true;
220 }
221 }
222 else
223 {
224 bz_sendTextMessagef (BZ_SERVER, playerID, "Not a correct value");
225 return true;
226 }
227
228 return true;
229
230 }
231
Init(const char * commandLine)232 void TimeLimit::Init ( const char* commandLine )
233 {
234 parseCommand(commandLine);
235
236 saveTimeLimit = bz_getTimeLimit();
237
238 bz_registerCustomSlashCommand ("timelimit",this);
239 Register(bz_ePlayerJoinEvent);
240 Register(bz_eGameEndEvent);
241 }
242
243
Cleanup(void)244 void TimeLimit::Cleanup ( void )
245 {
246
247 // set default timelimit back before unloading
248 //bz_setTimeLimit(saveTimeLimit);
249
250 bz_removeCustomSlashCommand ("timelimit");
251 Flush();
252
253
254 // set default timelimit back before unloading
255 bz_setTimeLimit(saveTimeLimit);
256 }
257
258 // Local Variables: ***
259 // mode: C++ ***
260 // tab-width: 4 ***
261 // c-basic-offset: 4 ***
262 // indent-tabs-mode: nil ***
263 // End: ***
264 // ex: shiftwidth=4 tabstop=4
265