Update weapon skin with CSQC
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / wepent.qc
1 #include "wepent.qh"
2
3 #define WEPENT_SET_NORMAL(var, x) MACRO_BEGIN \
4         var = x; \
5 MACRO_END
6
7 // #define PROP(public, fld, set, sv, cl)
8 #define WEPENT_NETPROPS(PROP) PROP(false, sv_entnum, WEPENT_SET_NORMAL, {}, {}) /* sentinel */ \
9         PROP(false, m_switchweapon, WEPENT_SET_NORMAL, \
10         { WriteByte(chan, this.m_switchweapon.m_id); }, \
11         { (viewmodels[this.m_wepent_slot]).switchweapon = Weapons_from(ReadByte()); }) \
12     \
13     PROP(false, m_switchingweapon, WEPENT_SET_NORMAL, \
14         { WriteByte(chan, this.m_switchingweapon.m_id); }, \
15         { (viewmodels[this.m_wepent_slot]).switchingweapon = Weapons_from(ReadByte()); }) \
16     \
17     PROP(false, m_weapon, WEPENT_SET_NORMAL, \
18         { WriteByte(chan, this.m_weapon.m_id); }, \
19         { (viewmodels[this.m_wepent_slot]).activeweapon = Weapons_from(ReadByte()); }) \
20     \
21     PROP(false, m_alpha, WEPENT_SET_NORMAL, \
22         { WriteByte(chan, rint(bound(-1, 254 * this.m_alpha, 254) - -1)); }, \
23         { (viewmodels[this.m_wepent_slot]).m_alpha = (ReadByte() + -1) / 254; }) \
24     \
25     PROP(false, vortex_charge, WEPENT_SET_NORMAL, \
26         { WriteByte(chan, this.vortex_charge * 255); }, \
27         { (viewmodels[this.m_wepent_slot]).vortex_charge = ReadByte() / 255; }) \
28     \
29     PROP(false, oknex_charge, WEPENT_SET_NORMAL, \
30         { WriteByte(chan, this.oknex_charge * 16); }, \
31         { (viewmodels[this.m_wepent_slot]).oknex_charge = ReadByte() / 16; }) \
32     \
33     PROP(false, m_gunalign, WEPENT_SET_NORMAL, \
34         { WriteByte(chan, this.m_gunalign); }, \
35         { (viewmodels[this.m_wepent_slot]).m_gunalign = ReadByte(); }) \
36     \
37     PROP(false, porto_v_angle_held, WEPENT_SET_NORMAL, \
38         { WriteByte(chan, this.porto_v_angle_held); if(this.porto_v_angle_held) { \
39                  WriteAngle(chan, this.owner.porto_v_angle.x); WriteAngle(chan, this.owner.porto_v_angle.y); \
40                 } }, \
41         { (viewmodels[this.m_wepent_slot]).angles_held_status = ReadByte(); if((viewmodels[this.m_wepent_slot]).angles_held_status) { \
42                 (viewmodels[this.m_wepent_slot]).angles_held = vec2(ReadAngle(), ReadAngle()); } \
43                 else { (viewmodels[this.m_wepent_slot]).angles_held = '0 0 0'; } }) \
44     \
45     PROP(false, tuba_instrument, WEPENT_SET_NORMAL, \
46         { WriteByte(chan, this.tuba_instrument); }, \
47         { (viewmodels[this.m_wepent_slot]).tuba_instrument = ReadByte(); }) \
48     \
49     PROP(false, hagar_load, WEPENT_SET_NORMAL, \
50         { WriteByte(chan, this.hagar_load); }, \
51         { (viewmodels[this.m_wepent_slot]).hagar_load = ReadByte(); }) \
52     \
53     PROP(false, minelayer_mines, WEPENT_SET_NORMAL, \
54         { WriteByte(chan, this.minelayer_mines); }, \
55         { (viewmodels[this.m_wepent_slot]).minelayer_mines = ReadByte(); }) \
56     \
57     PROP(false, arc_heat_percent, WEPENT_SET_NORMAL, \
58         { WriteByte(chan, this.arc_heat_percent * 255); }, \
59         { (viewmodels[this.m_wepent_slot]).arc_heat_percent = ReadByte() / 255; }) \
60     \
61     PROP(false, vortex_chargepool_ammo, WEPENT_SET_NORMAL, \
62         { WriteByte(chan, this.vortex_chargepool_ammo * 16); }, \
63         { (viewmodels[this.m_wepent_slot]).vortex_chargepool_ammo = ReadByte() / 16; }) \
64     \
65         PROP(false, oknex_chargepool_ammo, WEPENT_SET_NORMAL, \
66         { WriteByte(chan, this.oknex_chargepool_ammo * 16); }, \
67         { (viewmodels[this.m_wepent_slot]).oknex_chargepool_ammo = ReadByte() / 16; }) \
68     \
69         PROP(false, clip_load, WEPENT_SET_NORMAL, \
70         { WriteShort(chan, this.clip_load); }, \
71         { (viewmodels[this.m_wepent_slot]).clip_load = ReadShort(); }) \
72     \
73     PROP(false, clip_size, WEPENT_SET_NORMAL, \
74         { WriteShort(chan, this.clip_size); }, \
75         { (viewmodels[this.m_wepent_slot]).clip_size = ReadShort(); }) \
76     \
77     PROP(false, skin, WEPENT_SET_NORMAL, \
78         { WriteShort(chan, this.skin); }, \
79         { (viewmodels[this.m_wepent_slot]).m_skin = ReadShort(); }) \
80     \
81         /**/
82
83 #ifdef SVQC
84
85         int WEPENT_PUBLICMASK = 0;
86         STATIC_INIT(WEPENT_PUBLICMASK)
87         {
88                 int i = 0;
89                 #define X(public, fld, set, sv, cl) { \
90                         if (public) { \
91                                 WEPENT_PUBLICMASK |= BIT(i); \
92                         } \
93                         i += 1; \
94                 }
95                 WEPENT_NETPROPS(X);
96         #undef X
97                 if (i >= BITS(24 - 1)) LOG_FATAL("Exceeded WEPENT_NETPROPS limit");
98         }
99
100         bool _wepent_send(entity this, entity to, int sf, int chan)
101         {
102                 sf |= this.m_forceupdate;
103                 this.m_forceupdate = 0;
104                 if (chan == MSG_ENTITY)
105                         WriteHeader(chan, ENT_CLIENT_WEPENT);
106                 else
107                         WriteHeader(chan, CLIENT_WEPENT);
108                 .entity weaponentity = this.owner.weaponentity_fld;
109                 WriteByte(chan, weaponslot(weaponentity));
110                 WriteInt24_t(chan, sf);
111                 int i = 0;
112                 #define X(public, fld, set, sv, cl) { \
113                         if (sf & BIT(i)) { \
114                                 sv; \
115                         } \
116                         i += 1; \
117                 }
118                 WEPENT_NETPROPS(X);
119         #undef X
120                 return true;
121         }
122
123         bool wepent_send(entity this, entity to, int sf)
124         {
125                 return _wepent_send(this, to, sf, MSG_ENTITY);
126         }
127
128         void wepent_think(entity this)
129         {
130                 if(wasfreed(this.owner) || !this.owner)
131                 {
132                         delete(this);
133                         return;
134                 }
135
136                 this.nextthink = time;
137
138                 entity o = this.owner;
139
140                 int i = 0;
141                 #define X(public, fld, set, sv, cl) { \
142                         if (this.fld != o.fld) { \
143                                 set(this.fld, o.fld); \
144                                 this.SendFlags |= BIT(i); \
145                         } \
146                         i += 1; \
147                 }
148                 WEPENT_NETPROPS(X);
149         #undef X
150         }
151
152         bool wepent_customize(entity this, entity client)
153         {
154                 entity e = WaypointSprite_getviewentity(client);
155                 .entity weaponentity = this.owner.weaponentity_fld;
156                 return e.(weaponentity) == this.owner;
157         }
158
159         void wepent_link(entity wep)
160         {
161                 entity e = new(wepent_sender);
162                 e.owner = wep;
163                 setthink(e, wepent_think);
164                 e.nextthink = time;
165                 //e.drawonlytoclient = wep.owner;
166                 setcefc(e, wepent_customize);
167                 Net_LinkEntity(e, false, 0, wepent_send);
168         }
169
170 #endif
171
172 #ifdef CSQC
173
174         bool ReadWepent(entity this)
175         {
176                 int slot = ReadByte();
177                 this.m_wepent_slot = slot;
178                 viewmodels[slot].m_wepent_slot = slot;
179                 int sf = ReadInt24_t();
180                 int i = 0;
181                 #define X(public, fld, set, sv, cl) { \
182                         if (sf & BIT(i)) { \
183                                 cl; \
184                         } \
185                         i += 1; \
186                 }
187                 WEPENT_NETPROPS(X);
188         #undef X
189                 return true;
190         }
191
192         NET_HANDLE(ENT_CLIENT_WEPENT, bool isnew)
193         {
194                 if (isnew)
195                         this.classname = "wepent_receiver";
196                 return ReadWepent(this);
197         }
198
199         NET_HANDLE(CLIENT_WEPENT, bool isnew)
200         {
201                 return ReadWepent(NULL);
202         }
203
204 #endif