]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/items/spawning.qc
Add a more optimised and generic function to initialise items (loot or permanent)
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / items / spawning.qc
1 #include "spawning.qh"
2
3 /// \file
4 /// \brief Source file that contains implementation of the functions related to
5 /// creation of game items.
6 /// \copyright GNU GPLv2 or any later version.
7
8 #include <common/mapobjects/subs.qh>
9 #include <common/weapons/all.qh>
10 #include <server/items/items.qh>
11 #include <server/mutators/_mod.qh>
12 #include <server/weapons/spawning.qh>
13 #include <server/world.qh>
14
15 .bool m_isloot; ///< Holds whether item is loot.
16 /// \brief Holds whether strength, shield or superweapon timers expire while
17 /// this item is on the ground.
18 .bool m_isexpiring;
19
20 entity Item_FindDefinition(string class_name)
21 {
22         FOREACH(Items, it.m_canonical_spawnfunc == class_name,
23         {
24                 return it;
25         });
26         FOREACH(Weapons, it.m_canonical_spawnfunc == class_name,
27         {
28                 return it.m_pickup;
29         });
30         return NULL;
31 }
32
33 entity Item_DefinitionFromInternalName(string item_name)
34 {
35         FOREACH(Items, it.netname == item_name,
36         {
37                 return it;
38         });
39         FOREACH(Weapons, it.netname == item_name,
40         {
41                 return it.m_pickup;
42         });
43         return NULL;
44 }
45
46 bool Item_IsAllowed(string class_name)
47 {
48         entity definition = Item_FindDefinition(class_name);
49         if (definition == NULL)
50         {
51                 return false;
52         }
53         return Item_IsDefinitionAllowed(definition);
54 }
55
56 bool Item_IsDefinitionAllowed(entity definition)
57 {
58         return !MUTATOR_CALLHOOK(FilterItemDefinition, definition);
59 }
60
61 entity Item_Create(string class_name, vector position, bool no_align)
62 {
63         entity item = spawn();
64         item.classname = class_name;
65         item.spawnfunc_checked = true;
66         setorigin(item, position);
67         item.noalign = no_align;
68         Item_Initialize(item, class_name);
69         if (wasfreed(item))
70         {
71                 return NULL;
72         }
73         return item;
74 }
75
76 void Item_Initialize(entity item, string class_name)
77 {
78         FOREACH(Weapons, it.m_canonical_spawnfunc == class_name,
79         {
80                 weapon_defaultspawnfunc(item, it);
81                 return;
82         });
83         FOREACH(Items, it.m_canonical_spawnfunc == class_name,
84         {
85                 StartItem(item, it);
86                 return;
87         });
88         LOG_FATALF("Item_Initialize: Invalid classname: %s", class_name);
89 }
90
91 entity Item_CreateLoot(string class_name, vector position, vector vel,
92         float time_to_live)
93 {
94         entity item = spawn();
95         if (!Item_InitializeLoot(item, class_name, position, vel, time_to_live))
96         {
97                 return NULL;
98         }
99         return item;
100 }
101
102 bool Item_InitializeLoot(entity item, string class_name, vector position,
103         vector vel, float time_to_live)
104 {
105         item.classname = class_name;
106         Item_SetLoot(item, true);
107         item.noalign = true;
108         setorigin(item, position);
109         item.pickup_anyway = true;
110         item.spawnfunc_checked = true;
111         Item_Initialize(item, class_name);
112         if (wasfreed(item))
113         {
114                 return false;
115         }
116         item.gravity = 1;
117         item.velocity = vel;
118         // StartItem sets the default .wait expiry time which is respected by Item_Think()
119         if (time_to_live)
120                 item.wait = time + time_to_live;
121         return true;
122 }
123
124 // An optimised and generic way to initialise items (loot or permanent)
125 // required field: itemdef (faster, preferred) OR classname
126 // optional fields: origin, velocity, lifetime, noalign
127 // lifetime < 0 means permanent (not loot), lifetime > 0 overrides the default
128 // permanent items only: noalign means the item is suspended (won't drop to floor)
129 bool Item_Initialise(entity item)
130 {
131         if (item.lifetime >= 0)
132         {
133                 Item_SetLoot(item, true);
134                 item.pickup_anyway = true; // these are ALWAYS pickable
135         }
136
137         if (item.itemdef) // no search required
138         {
139                 if (item.itemdef.instanceOfWeapon)
140                         weapon_defaultspawnfunc(item, item.itemdef);
141                 else
142                         StartItem(item, item.itemdef);
143         }
144         else // fall back to classname search
145         {
146                 FOREACH(Weapons, it.m_canonical_spawnfunc == item.classname,
147                 {
148                         weapon_defaultspawnfunc(item, it);
149                         goto classname_found;
150                 });
151                 FOREACH(Items, it.m_canonical_spawnfunc == item.classname,
152                 {
153                         StartItem(item, it);
154                         goto classname_found;
155                 });
156                 LOG_FATALF("Item_Initialize: Invalid classname: %s", item.classname);
157                 LABEL(classname_found)
158         }
159
160         if (wasfreed(item))
161                 return false;
162
163         // StartItem sets the default .wait expiry time which is respected by Item_Think()
164         if (item.lifetime > 0)
165                 item.wait = time + item.lifetime;
166
167         item.spawnfunc_checked = true;
168         return true;
169 }
170
171 bool Item_IsLoot(entity item)
172 {
173         return item.m_isloot || item.classname == "droppedweapon";
174 }
175
176 void Item_SetLoot(entity item, bool loot)
177 {
178         item.m_isloot = loot;
179 }
180
181 bool Item_ShouldKeepPosition(entity item)
182 {
183         return item.noalign || (item.spawnflags & 1);
184 }
185
186 bool Item_IsExpiring(entity item)
187 {
188         return item.m_isexpiring;
189 }
190
191 void Item_SetExpiring(entity item, bool expiring)
192 {
193         item.m_isexpiring = expiring;
194 }
195
196 // Compatibility spawn functions
197
198 // in Quake this is green armor, in Xonotic maps it is an armor shard
199 SPAWNFUNC_ITEM_COND(item_armor1, autocvar_sv_mapformat_is_quake3, ITEM_ArmorSmall, ITEM_ArmorMedium)
200 SPAWNFUNC_ITEM(item_armor25, ITEM_ArmorMega) // Nexuiz used item_armor25 to spawn a Mega Armor
201 SPAWNFUNC_ITEM(item_health1, ITEM_HealthSmall)
202 SPAWNFUNC_ITEM(item_health25, ITEM_HealthMedium)
203 SPAWNFUNC_ITEM(item_health100, ITEM_HealthMega)
204 SPAWNFUNC_ITEM(item_armor_large, ITEM_ArmorMega)
205 SPAWNFUNC_ITEM(item_health_large, ITEM_HealthBig)