Merge branch 'master' into martin-t/globals
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / announcer.qc
1 #include "announcer.qh"
2
3 #include <client/mutators/_mod.qh>
4
5 #include <common/notifications/all.qh>
6 #include <common/stats.qh>
7
8 bool announcer_1min;
9 bool announcer_5min;
10 string AnnouncerOption()
11 {
12         string ret = autocvar_cl_announcer;
13         MUTATOR_CALLHOOK(AnnouncerOption, ret);
14         ret = M_ARGV(0, string);
15         return ret;
16 }
17
18 entity announcer_countdown;
19
20 void Announcer_Countdown(entity this)
21 {
22         float starttime = STAT(GAMESTARTTIME);
23         float roundstarttime = STAT(ROUNDSTARTTIME);
24         if(roundstarttime == -1)
25         {
26                 Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_ROUNDSTOP);
27                 delete(this);
28                 announcer_countdown = NULL;
29                 return;
30         }
31         if(roundstarttime >= starttime)
32                 starttime = roundstarttime;
33         if(starttime <= time && roundstarttime != starttime) // game start time has passed
34                 announcer_5min = announcer_1min = false; // reset maptime announcers now as well
35
36         float countdown = (starttime - time);
37         float countdown_rounded = floor(0.5 + countdown);
38
39         if(countdown <= 0) // countdown has finished, starttime is now
40         {
41                 Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_BEGIN);
42                 Local_Notification(MSG_MULTI, MULTI_COUNTDOWN_BEGIN);
43                 delete(this);
44                 announcer_countdown = NULL;
45                 return;
46         }
47         else // countdown is still going
48         {
49                 // if concomitant countdown to round start overrides countdown to game start
50                 if(roundstarttime == starttime)
51                 {
52                         Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_ROUNDSTART, countdown_rounded);
53                         Notification annce_num = Announcer_PickNumber(CNT_ROUNDSTART, countdown_rounded);
54                         if(annce_num != NULL)
55                                 Local_Notification(MSG_ANNCE, annce_num);
56                 }
57                 else
58                 {
59                         Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_GAMESTART, countdown_rounded);
60                         Notification annce_num = Announcer_PickNumber(CNT_GAMESTART, countdown_rounded);
61                         if(annce_num != NULL)
62                                 Local_Notification(MSG_ANNCE, annce_num);
63                 }
64
65                 this.nextthink = (starttime - (countdown - 1));
66         }
67 }
68
69 /**
70  * Checks whether the server initiated a map restart (stat_game_starttime changed)
71  *
72  * TODO: Use a better solution where a common shared entitiy is used that contains
73  * timelimit, fraglimit and game_starttime! Requires engine changes (remove STAT_TIMELIMIT
74  * and STAT_FRAGLIMIT to be auto-sent)
75  */
76  float previous_game_starttime;
77 void Announcer_Gamestart()
78 {
79         float startTime = STAT(GAMESTARTTIME);
80         float roundstarttime = STAT(ROUNDSTARTTIME);
81         if(roundstarttime > startTime)
82                 startTime = roundstarttime;
83         if(intermission)
84         {
85                 if(announcer_countdown)
86                 {
87                         centerprint_kill(ORDINAL(CPID_ROUND));
88                         if(announcer_countdown)
89                         {
90                                 delete(announcer_countdown);
91                                 announcer_countdown = NULL;
92                         }
93                 }
94                 return;
95         }
96
97         if(previous_game_starttime != startTime)
98         {
99                 if(time < startTime)
100                 {
101                         if (!announcer_countdown)
102                         {
103                                 announcer_countdown = new(announcer_countdown);
104                                 setthink(announcer_countdown, Announcer_Countdown);
105                         }
106
107                         if(time + 5.0 < startTime) // if connecting to server while restart was active don't always play prepareforbattle
108                         if(time > announcer_countdown.nextthink) // don't play it again if countdown was already going
109                                 Local_Notification(MSG_ANNCE, ANNCE_PREPARE);
110
111                         announcer_countdown.nextthink = startTime - floor(startTime - time); //synchronize nextthink to startTime
112                 }
113         }
114
115         previous_game_starttime = startTime;
116 }
117
118 #define ANNOUNCER_CHECKMINUTE(minute) MACRO_BEGIN \
119         if(announcer_##minute##min) { \
120                 if(timeleft > minute * 60) \
121                         announcer_##minute##min = false; \
122         } else { \
123                 if(timeleft < minute * 60 && timeleft > minute * 60 - 1) { \
124                         announcer_##minute##min = true; \
125                         Local_Notification(MSG_ANNCE, ANNCE_REMAINING_MIN_##minute); \
126                 } \
127         } \
128 MACRO_END
129
130 void Announcer_Time()
131 {
132         if(intermission)
133                 return;
134
135         float timeleft;
136         if(warmup_stage)
137         {
138                 float warmup_timelimit = STAT(WARMUP_TIMELIMIT);
139                 if(warmup_timelimit > 0)
140                         timeleft = max(0, warmup_timelimit - time);
141                 else
142                         timeleft = 0;
143         }
144         else
145                 timeleft = max(0, STAT(TIMELIMIT) * 60 + STAT(GAMESTARTTIME) - time);
146
147         if(autocvar_cl_announcer_maptime >= 2)
148                 ANNOUNCER_CHECKMINUTE(5);
149
150         if((autocvar_cl_announcer_maptime == 1) || (autocvar_cl_announcer_maptime == 3))
151                 ANNOUNCER_CHECKMINUTE(1);
152 }
153
154 void Announcer()
155 {
156         Announcer_Gamestart();
157         Announcer_Time();
158 }