]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/mutators/mutator/gamemode_singleplayer.qc
Prevent bots from picking up items on single player
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / mutator / gamemode_singleplayer.qc
1 #include "gamemode_singleplayer.qh"
2
3 const int SP_TEAM_PLAYER = NUM_TEAM_1;
4 const int SP_TEAM_ENEMY = NUM_TEAM_2;
5
6 .bool can_drop_weapon;
7 .string weapon_name;
8 .int sp_spawn_team;
9 .entity sp_spawn_spot;
10 .bool can_respawn;
11
12 bool autocvar_g_sp_allow_bot_pickup;
13
14 int sp_bot_number;
15
16 /*QUAKED spawnfunc_tdm_team (0 .5 .8) (-16 -16 -24) (16 16 32)
17 Team declaration for TDM gameplay, this allows you to decide what team names and control point models are used in your map.
18 Note: If you use spawnfunc_tdm_team entities you must define at least 2!  However, unlike domination, you don't need to make a blank one too.
19 Keys:
20 "netname" Name of the team (for example Red, Blue, Green, Yellow, Life, Death, Offense, Defense, etc)...
21 "cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
22 spawnfunc(sp_team)
23 {
24     if(!g_singleplayer || !this.cnt) { delete(this); return; }
25
26     this.classname = "sp_team";
27     this.team = this.cnt + 1;
28 }
29
30 // code from here on is just to support maps that don't have team entities
31 void sp_spawn_team_entity(string teamname, int teamcolor)
32 {
33     entity this = new_pure(sp_team);
34     this.netname = teamname;
35     this.cnt = teamcolor - 1;
36     this.team = teamcolor;
37     this.spawnfunc_checked = true;
38 }
39
40 // spawnfuncs
41 spawnfunc(info_player_singleplayer)
42 {
43     if (!g_singleplayer) { delete(this); return; }
44
45     this.team = SP_TEAM_PLAYER;
46     this.sp_spawn_team = SP_TEAM_PLAYER;
47     spawnfunc_info_player_deathmatch(this);
48 }
49
50 void sp_spawn_bot(entity spawn_point)
51 {
52     sp_bot_number++;
53     entity bot = spawnclient();
54     if (bot)
55     {
56         bot.sp_spawn_spot = spawn_point;
57         bot_spawn_setup(bot);
58     }
59     else
60     {
61         LOG_WARN("Could not spawn bot");
62     }
63 }
64
65 void sp_enemy_spawn_think(entity this)
66 {
67     sp_spawn_bot(this);
68     setthink(this, func_null);
69 }
70
71
72 void sp_enemy_spawn_use(entity this, entity actor, entity trigger)
73 {
74     sp_spawn_bot(this);
75 }
76
77 spawnfunc(info_player_singleplayer_enemy)
78 {
79         if (!g_singleplayer) { delete(this); return; }
80
81         this.team = SP_TEAM_ENEMY;
82     this.sp_spawn_team = SP_TEAM_ENEMY;
83         spawnfunc_info_player_deathmatch(this);
84     this.use = sp_enemy_spawn_use;
85     if ( this.targetname == "" )
86         setthink(this, sp_enemy_spawn_think);
87 }
88
89 void sp_delayed_init(entity this)
90 {
91     // if no teams are found, spawn defaults
92     if(find(NULL, classname, "sp_team") == NULL)
93     {
94         sp_spawn_team_entity("Player", SP_TEAM_PLAYER);
95         sp_spawn_team_entity("Enemy", SP_TEAM_ENEMY);
96     }
97
98     sp_bot_number = 0;
99 }
100
101 void sp_remove_bot(entity bot)
102 {
103     sp_bot_number--;
104     bot.sp_spawn_spot = NULL;
105     bot_clear(bot);
106 }
107
108 MUTATOR_HOOKFUNCTION(sp, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
109 {
110         M_ARGV(1, string) = "sp_team";
111     entity ent = M_ARGV(2, entity);
112     if ( IS_BOT_CLIENT(ent) )
113     {
114         ent.team_forced = NUM_TEAM_2;
115     }
116     else if( IS_REAL_CLIENT(ent) )
117     {
118         ent.team_forced = NUM_TEAM_1;
119         c1 = 1;
120         c2 = 0;
121         c3 = 0;
122         c4 = 0;
123     }
124     return true;
125 }
126
127 MUTATOR_HOOKFUNCTION(sp, Scores_CountFragsRemaining)
128 {
129     return false;
130 }
131
132 MUTATOR_HOOKFUNCTION(sp, PlayerSpawn)
133 {
134     entity player = M_ARGV(0, entity);
135     entity spawn_spot = M_ARGV(1, entity);
136     if ( IS_BOT_CLIENT(player) )
137     {
138         player.can_drop_weapon = spawn_spot.can_drop_weapon;
139         player.items |= IT_UNLIMITED_WEAPON_AMMO;
140         if ( spawn_spot.health )
141             player.health = spawn_spot.health;
142         player.armorvalue = spawn_spot.armorvalue;
143         player.weapons = WepSet_FromWeapon(Weapons_fromstr(spawn_spot.weapon_name));
144         if ( spawn_spot.netname )
145             player.netname = spawn_spot.netname;
146     }
147     else
148     {
149         player.can_drop_weapon = true;
150     }
151 }
152
153 MUTATOR_HOOKFUNCTION(sp, ForbidDropCurrentWeapon)
154 {
155     entity player = M_ARGV(0, entity);
156     return !player.can_drop_weapon;
157 }
158
159 MUTATOR_HOOKFUNCTION(sp, CheckRules_World)
160 {
161     M_ARGV(0, float) = WINNING_NO;
162     // TODO: conditions for WINNING_YES
163     return true;
164 }
165
166 MUTATOR_HOOKFUNCTION(sp, Spawn_Score)
167 {
168     entity player = M_ARGV(0, entity);
169     entity spawn_spot = M_ARGV(1, entity);
170     vector spawn_score = M_ARGV(2, vector);
171     if ( IS_BOT_CLIENT(player) )
172     {
173         if ( spawn_spot.sp_spawn_team != SP_TEAM_ENEMY ||
174             (player.sp_spawn_spot && player.sp_spawn_spot != spawn_spot) )
175             spawn_score.x = -1;
176     }
177     else if ( spawn_spot.sp_spawn_team != SP_TEAM_PLAYER )
178     {
179         spawn_score.x = -1;
180     }
181
182     M_ARGV(2, vector) = spawn_score;
183 }
184
185 MUTATOR_HOOKFUNCTION(sp, HideTeamNagger)
186 {
187     return true;
188 }
189
190 MUTATOR_HOOKFUNCTION(sp, Bot_FixCount)
191 {
192     M_ARGV(2, int) = sp_bot_number;
193     return true;
194 }
195
196 MUTATOR_HOOKFUNCTION(sp, PlayerDies)
197 {
198     entity target = M_ARGV(2, entity);
199     if ( IS_BOT_CLIENT(target) )
200     {
201         if ( target.sp_spawn_spot && !target.sp_spawn_spot.can_respawn )
202         {
203             sp_remove_bot(target);
204         }
205     }
206 }
207
208 MUTATOR_HOOKFUNCTION(sp, Bot_SelectRemove)
209 {
210     FOREACH_CLIENT(it.isbot,
211     {
212         if ( !it.sp_spawn_spot )
213         {
214             M_ARGV(0, entity) = it;
215             return;
216         }
217     });
218 }
219
220 MUTATOR_HOOKFUNCTION(sp, PlayerPreThink)
221 {
222     entity player = M_ARGV(0, entity);
223     if ( IS_BOT_CLIENT(player) && !player.sp_spawn_spot )
224         bot_remove(player);
225 }
226
227 MUTATOR_HOOKFUNCTION(sp, ItemTouch)
228 {
229     entity toucher = M_ARGV(1, entity);
230     if ( IS_BOT_CLIENT(toucher) && !autocvar_g_sp_allow_bot_pickup )
231         return MUT_ITEMTOUCH_RETURN;
232     return MUT_ITEMTOUCH_CONTINUE;
233 }
234
235 MUTATOR_HOOKFUNCTION(sp, Item_Spawn)
236 {
237     entity item = M_ARGV(0, entity);
238     if ( !autocvar_g_sp_allow_bot_pickup )
239     {
240         item.bot_pickup = false;
241     }
242     return false;
243 }