Cube  Check-in [d3b4b2d476]

Overview
Comment:Migrate projectile to a class
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: d3b4b2d476d809f7ab00502eed47614c949264690b3eccc7a96c73687d0f05bf
User & Date: js on 2025-03-09 11:24:01
Other Links: manifest | tags
Context
2025-03-09
18:57
Convert dynent to a class check-in: d2b3ff790f user: js tags: trunk
11:24
Migrate projectile to a class check-in: d3b4b2d476 user: js tags: trunk
10:25
Use SDL_TextInputEvent for input check-in: 4c092023dc user: js tags: trunk
Changes

Added src/Projectile.h version [28cf35ad48].

Added src/Projectile.m version [902fed7b64].

Modified src/meson.build from [b573376159] to [2625064d57].

1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19











+







executable('client',
  [
    'Alias.m',
    'Command.mm',
    'Cube.mm',
    'Identifier.m',
    'KeyMapping.m',
    'MD2.mm',
    'MapModelInfo.m',
    'Menu.m',
    'MenuItem.m',
    'Projectile.m',
    'Variable.mm',
    'client.mm',
    'clientextras.mm',
    'clientgame.mm',
    'clients2c.mm',
    'commands.mm',
    'console.mm',

Modified src/protos.h from [8800716a44] to [455fc77430].

121
122
123
124
125
126
127
128
129


130
131
132
133
134
135
136
121
122
123
124
125
126
127


128
129
130
131
132
133
134
135
136







-
-
+
+







extern void resettagareas();
extern void settagareas();
extern entity *newentity(
    int x, int y, int z, OFString *what, int v1, int v2, int v3, int v4);

// worldlight
extern void calclight();
extern void dodynlight(
    OFVector3D &vold, OFVector3D &v, int reach, int strength, dynent *owner);
extern void dodynlight(const OFVector3D &vold, const OFVector3D &v, int reach,
    int strength, dynent *owner);
extern void cleardlights();
extern block *blockcopy(block &b);
extern void blockpaste(block &b);

// worldrender
extern void render_world(float vx, float vy, float vh, int yaw, int pitch,
    float widef, int w, int h);
162
163
164
165
166
167
168
169

170
171
172
173
174
175
176
177
178
179

180
181
182
183
184
185
186
162
163
164
165
166
167
168

169
170
171
172
173
174
175
176
177
178

179
180
181
182
183
184
185
186







-
+









-
+







extern void pruneundos(int maxremain = 0);

// renderextras
extern void line(int x1, int y1, float z1, int x2, int y2, float z2);
extern void box(block &b, float z1, float z2, float z3, float z4);
extern void dot(int x, int y, float z);
extern void linestyle(float width, int r, int g, int b);
extern void newsphere(OFVector3D &o, float max, int type);
extern void newsphere(const OFVector3D &o, float max, int type);
extern void renderspheres(int time);
extern void gl_drawhud(
    int w, int h, int curfps, int nquads, int curvert, bool underwater);
extern void readdepth(int w, int h);
extern void blendbox(int x1, int y1, int x2, int y2, bool border);
extern void damageblend(int n);

// renderparticles
extern void setorient(OFVector3D &r, OFVector3D &u);
extern void particle_splash(int type, int num, int fade, OFVector3D &p);
extern void particle_splash(int type, int num, int fade, const OFVector3D &p);
extern void particle_trail(
    int type, int fade, OFVector3D &from, OFVector3D &to);
extern void render_particles(int time);

// worldio
extern void save_world(OFString *fname);
extern void load_world(OFString *mname);
198
199
200
201
202
203
204
205

206
207
208
209
210
211
212
198
199
200
201
202
203
204

205
206
207
208
209
210
211
212







-
+







extern void moveplayer(dynent *pl, int moveres, bool local);
extern bool collide(dynent *d, bool spawn, float drop, float rise);
extern void entinmap(dynent *d);
extern void setentphysics(int mml, int mmr);
extern void physicsframe();

// sound
extern void playsound(int n, OFVector3D *loc = 0);
extern void playsound(int n, const OFVector3D *loc = NULL);
extern void playsoundc(int n);
extern void initsound();
extern void cleansound();

// rendermd2
extern void rendermodel(OFString *mdl, int frame, int range, int tex, float rad,
    float x, float y, float z, float yaw, float pitch, bool teammate,

Modified src/renderextras.mm from [3268694917] to [4ee74611a3].

85
86
87
88
89
90
91
92

93
94
95
96
97
98
99
85
86
87
88
89
90
91

92
93
94
95
96
97
98
99







-
+







	int type;
	sphere *next;
};
sphere spheres[MAXSPHERES], *slist = NULL, *sempty = NULL;
bool sinit = false;

void
newsphere(OFVector3D &o, float max, int type)
newsphere(const OFVector3D &o, float max, int type)
{
	if (!sinit) {
		loopi(MAXSPHERES)
		{
			spheres[i].next = sempty;
			sempty = &spheres[i];
		}

Modified src/renderparticles.mm from [b42cd85412] to [f46610835d].

11
12
13
14
15
16
17
18
19


20
21
22
23
24
25
26
11
12
13
14
15
16
17


18
19
20
21
22
23
24
25
26







-
-
+
+







	particle *next;
};
particle particles[MAXPARTICLES], *parlist = NULL, *parempty = NULL;
bool parinit = false;

VARP(maxparticles, 100, 2000, MAXPARTICLES - 500);

void
newparticle(OFVector3D &o, OFVector3D &d, int fade, int type)
static void
newparticle(const OFVector3D &o, const OFVector3D &d, int fade, int type)
{
	if (!parinit) {
		loopi(MAXPARTICLES)
		{
			particles[i].next = parempty;
			parempty = &particles[i];
		}
129
130
131
132
133
134
135
136

137
138
139
140
141
142
143
144
145
146
147

148
149
150
151
152
153
154
155
129
130
131
132
133
134
135

136
137
138
139
140
141
142
143
144
145
146

147

148
149
150
151
152
153
154







-
+










-
+
-








	glEnable(GL_FOG);
	glDisable(GL_BLEND);
	glDepthMask(GL_TRUE);
}

void
particle_splash(int type, int num, int fade, OFVector3D &p)
particle_splash(int type, int num, int fade, const OFVector3D &p)
{
	loopi(num)
	{
		const int radius = type == 5 ? 50 : 150;
		int x, y, z;
		do {
			x = rnd(radius * 2) - radius;
			y = rnd(radius * 2) - radius;
			z = rnd(radius * 2) - radius;
		} while (x * x + y * y + z * z > radius * radius);
		OFVector3D d = OFMakeVector3D(x, y, z);
		newparticle(p, OFMakeVector3D(x, y, z), rnd(fade * 3), type);
		newparticle(p, d, rnd(fade * 3), type);
	}
}

void
particle_trail(int type, int fade, OFVector3D &s, OFVector3D &e)
{
	vdist(d, v, s, e);

Modified src/sound.mm from [7dfddc04de] to [4f8b2c4c47].

88
89
90
91
92
93
94
95
96



97
98
99
100
101
102



103
104
105
106
107
108
109
88
89
90
91
92
93
94


95
96
97
98
99
100
101


102
103
104
105
106
107
108
109
110
111







-
-
+
+
+




-
-
+
+
+







		@autoreleasepool {
			OFString *path =
			    [OFString stringWithFormat:@"packages/%@", name];
			OFIRI *IRI = [Cube.sharedInstance.gameDataIRI
			    IRIByAppendingPathComponent:path];

#ifdef USE_MIXER
			if (mod = Mix_LoadMUS(
			        IRI.fileSystemRepresentation.UTF8String)) {
			if ((mod = Mix_LoadMUS(
			         IRI.fileSystemRepresentation.UTF8String)) !=
			    NULL) {
				Mix_PlayMusic(mod, -1);
				Mix_VolumeMusic((musicvol * MAXVOL) / 255);
			}
#else
			if (mod = FMUSIC_LoadSong(
			        IRI.fileSystemRepresentation.UTF8String)) {
			if ((mod = FMUSIC_LoadSong(
			         IRI.fileSystemRepresentation.UTF8String)) !=
			    NULL) {
				FMUSIC_PlaySong(mod);
				FMUSIC_SetMasterVolume(mod, musicvol);
			} else if (stream = FSOUND_Stream_Open(
			               IRI.fileSystemRepresentation.UTF8String,
			               FSOUND_LOOP_NORMAL, 0, 0)) {
				int chan =
				    FSOUND_Stream_Play(FSOUND_FREE, stream);
162
163
164
165
166
167
168
169
170


171
172
173
174
175
176
177
164
165
166
167
168
169
170


171
172
173
174
175
176
177
178
179







-
-
+
+







#else
	FSOUND_Close();
#endif
}

VAR(stereo, 0, 1, 1);

void
updatechanvol(int chan, OFVector3D *loc)
static void
updatechanvol(int chan, const OFVector3D *loc)
{
	int vol = soundvol, pan = 255 / 2;
	if (loc) {
		vdist(dist, v, *loc, player1->o);
		vol -= (int)(dist * 3 * soundvol /
		    255); // simple mono distance attenuation
		if (stereo && (v.x != 0 || v.y != 0)) {
190
191
192
193
194
195
196
197
198


199
200
201
202
203
204
205
192
193
194
195
196
197
198


199
200
201
202
203
204
205
206
207







-
-
+
+







	Mix_SetPanning(chan, 255 - pan, pan);
#else
	FSOUND_SetVolume(chan, vol);
	FSOUND_SetPan(chan, pan);
#endif
}

void
newsoundloc(int chan, OFVector3D *loc)
static void
newsoundloc(int chan, const OFVector3D *loc)
{
	assert(chan >= 0 && chan < MAXCHAN);
	soundlocs[chan].loc = *loc;
	soundlocs[chan].inuse = true;
}

void
226
227
228
229
230
231
232
233

234
235
236
237
238
239
240
228
229
230
231
232
233
234

235
236
237
238
239
240
241
242







-
+







	addmsg(0, 2, SV_SOUND, n);
	playsound(n);
}

int soundsatonce = 0, lastsoundmillis = 0;

void
playsound(int n, OFVector3D *loc)
playsound(int n, const OFVector3D *loc)
{
	if (nosound)
		return;
	if (!soundvol)
		return;
	if (lastmillis == lastsoundmillis)
		soundsatonce++;

Modified src/weapon.mm from [a095df6286] to [652afaa3f5].

1
2
3
4
5

6
7
8
9
10
11
12
13
14
15




16
17
18
19
20
21
22
1
2
3
4

5



6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22




-
+
-
-
-






-
+
+
+
+







// weapon.cpp: all shooting and effects code

#include "cube.h"

struct guninfo {
#import "Projectile.h"
	short sound, attackdelay, damage, projspeed, part, kickamount;
	OFString *name;
};

static const int MONSTERDAMAGEFACTOR = 4;
static const int SGRAYS = 20;
static const float SGSPREAD = 2;
static OFVector3D sg[SGRAYS];

static const guninfo guns[NUMGUNS] = {
static const struct {
	short sound, attackdelay, damage, projspeed, part, kickamount;
	OFString *name;
} guns[NUMGUNS] = {
	{ S_PUNCH1, 250, 50, 0, 0, 1, @"fist" },
	{ S_SG, 1400, 10, 0, 0, 20, @"shotgun" }, // *SGRAYS
	{ S_CG, 100, 30, 0, 0, 7, @"chaingun" },
	{ S_RLFIRE, 800, 120, 80, 0, 10, @"rocketlauncher" },
	{ S_RIFLE, 1500, 100, 0, 0, 30, @"rifle" },
	{ S_FLAUNCH, 200, 20, 50, 4, 1, @"fireball" },
	{ S_ICEBALL, 200, 40, 30, 6, 1, @"iceball" },
79
80
81
82
83
84
85

86
87

88
89
90


91
92
93
94
95
96
97
79
80
81
82
83
84
85
86
87

88

89

90
91
92
93
94
95
96
97
98







+

-
+
-

-
+
+







#define RNDD (rnd(101) - 50) * f
		OFVector3D r = OFMakeVector3D(RNDD, RNDD, RNDD);
		sg[i] = to;
		vadd(sg[i], r);
	}
}

// if lineseg hits entity bounding box
bool
intersect(dynent *d, OFVector3D &from,
intersect(dynent *d, const OFVector3D &from, const OFVector3D &to)
    OFVector3D &to) // if lineseg hits entity bounding box
{
	OFVector3D v = to, w = d->o, *p;
	OFVector3D v = to, w = d->o;
	const OFVector3D *p;
	vsub(v, from);
	vsub(w, from);
	float c1 = dotprod(w, v);

	if (c1 <= 0)
		p = &from;
	else {
124
125
126
127
128
129
130
131

132
133
134
135
136
137
138

139
140
141
142

143

144
145
146
147
148
149
150
151



152
153

154

155
156
157
158
159
160
161







162
163
164
165
166
167
168
125
126
127
128
129
130
131

132







133
134
135
136
137
138

139
140
141
142
143
144
145


146
147
148


149
150
151







152
153
154
155
156
157
158
159
160
161
162
163
164
165







-
+
-
-
-
-
-
-
-
+




+
-
+






-
-
+
+
+
-
-
+

+
-
-
-
-
-
-
-
+
+
+
+
+
+
+







		if (intersect(o, player1->o, worldpos))
			return @(o->name);
	}

	return nil;
}

const int MAXPROJ = 100;
static const size_t MAXPROJ = 100;
struct projectile {
	OFVector3D o, to;
	float speed;
	dynent *owner;
	int gun;
	bool inuse, local;
} projs[MAXPROJ];
static Projectile *projs[MAXPROJ];

void
projreset()
{
	for (size_t i = 0; i < MAXPROJ; i++)
	loopi(MAXPROJ) projs[i].inuse = false;
		projs[i].inuse = false;
}

void
newprojectile(OFVector3D &from, OFVector3D &to, float speed, bool local,
    dynent *owner, int gun)
{
	loopi(MAXPROJ)
	{
	for (size_t i = 0; i < MAXPROJ; i++) {
		Projectile *p = projs[i];

		projectile *p = &projs[i];
		if (p->inuse)
		if (p.inuse)
			continue;

		p->inuse = true;
		p->o = from;
		p->to = to;
		p->speed = speed;
		p->local = local;
		p->owner = owner;
		p->gun = gun;
		p.inuse = true;
		p.o = from;
		p.to = to;
		p.speed = speed;
		p.local = local;
		p.owner = owner;
		p.gun = gun;
		return;
	}
}

void
hit(int target, int damage, dynent *d, dynent *at)
{
177
178
179
180
181
182
183
184
185


186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203


204
205
206
207


208
209
210
211
212
213
214


215
216

217
218
219
220
221
222
223
224

225
226
227
228

229
230
231
232
233

234
235
236
237
238
239



240
241
242
243
244
245
246
247



248
249

250

251
252


253
254
255


256
257
258
259

260
261
262
263
264
265
266
267
268

269
270
271
272

273
274
275

276
277

278
279
280


281
282
283
284
285

286
287
288
289

290
291
292
293
294
295
296
174
175
176
177
178
179
180


181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198


199
200
201
202


203
204
205
206
207
208
209


210
211
212

213
214
215
216
217
218
219
220

221
222
223
224

225
226
227
228
229

230
231
232
233



234
235
236
237
238
239
240
241
242


243
244
245


246
247
248


249
250
251


252
253
254
255
256

257
258
259
260
261
262
263
264
265

266
267
268
269

270
271
272

273
274

275
276


277
278
279
280
281
282

283
284
285
286

287
288
289
290
291
292
293
294







-
-
+
+
















-
-
+
+


-
-
+
+





-
-
+
+

-
+







-
+



-
+




-
+



-
-
-
+
+
+






-
-
+
+
+
-
-
+

+
-
-
+
+

-
-
+
+



-
+








-
+



-
+


-
+

-
+

-
-
+
+




-
+



-
+







	particle_splash(3, damage, 1000, d->o);
	demodamage(damage, d->o);
}

const float RL_RADIUS = 5;
const float RL_DAMRAD = 7; // hack

void
radialeffect(dynent *o, OFVector3D &v, int cn, int qdam, dynent *at)
static void
radialeffect(dynent *o, const OFVector3D &v, int cn, int qdam, dynent *at)
{
	if (o->state != CS_ALIVE)
		return;
	vdist(dist, temp, v, o->o);
	dist -= 2; // account for eye distance imprecision
	if (dist < RL_DAMRAD) {
		if (dist < 0)
			dist = 0;
		int damage = (int)(qdam * (1 - (dist / RL_DAMRAD)));
		hit(cn, damage, o, at);
		vmul(temp, (RL_DAMRAD - dist) * damage / 800);
		vadd(o->vel, temp);
	}
}

void
splash(projectile *p, OFVector3D &v, OFVector3D &vold, int notthisplayer,
    int notthismonster, int qdam)
splash(Projectile *p, const OFVector3D &v, const OFVector3D &vold,
    int notthisplayer, int notthismonster, int qdam)
{
	particle_splash(0, 50, 300, v);
	p->inuse = false;
	if (p->gun != GUN_RL) {
	p.inuse = false;
	if (p.gun != GUN_RL) {
		playsound(S_FEXPLODE, &v);
		// no push?
	} else {
		playsound(S_RLHIT, &v);
		newsphere(v, RL_RADIUS, 0);
		dodynlight(vold, v, 0, 0, p->owner);
		if (!p->local)
		dodynlight(vold, v, 0, 0, p.owner);
		if (!p.local)
			return;
		radialeffect(player1, v, -1, qdam, p->owner);
		radialeffect(player1, v, -1, qdam, p.owner);
		loopv(players)
		{
			if (i == notthisplayer)
				continue;
			dynent *o = players[i];
			if (!o)
				continue;
			radialeffect(o, v, i, qdam, p->owner);
			radialeffect(o, v, i, qdam, p.owner);
		}
		dvector &mv = getmonsters();
		loopv(mv) if (i != notthismonster)
		    radialeffect(mv[i], v, i, qdam, p->owner);
		    radialeffect(mv[i], v, i, qdam, p.owner);
	}
}

inline void
projdamage(dynent *o, projectile *p, OFVector3D &v, int i, int im, int qdam)
projdamage(dynent *o, Projectile *p, OFVector3D &v, int i, int im, int qdam)
{
	if (o->state != CS_ALIVE)
		return;
	if (intersect(o, p->o, v)) {
		splash(p, v, p->o, i, im, qdam);
		hit(i, qdam, o, p->owner);
	if (intersect(o, p.o, v)) {
		splash(p, v, p.o, i, im, qdam);
		hit(i, qdam, o, p.owner);
	}
}

void
moveprojectiles(float time)
{
	loopi(MAXPROJ)
	{
	for (size_t i = 0; i < MAXPROJ; i++) {
		Projectile *p = projs[i];

		projectile *p = &projs[i];
		if (!p->inuse)
		if (!p.inuse)
			continue;

		int qdam = guns[p->gun].damage * (p->owner->quadmillis ? 4 : 1);
		if (p->owner->monsterstate)
		int qdam = guns[p.gun].damage * (p.owner->quadmillis ? 4 : 1);
		if (p.owner->monsterstate)
			qdam /= MONSTERDAMAGEFACTOR;
		vdist(dist, v, p->o, p->to);
		float dtime = dist * 1000 / p->speed;
		vdist(dist, v, p.o, p.to);
		float dtime = dist * 1000 / p.speed;
		if (time > dtime)
			dtime = time;
		vmul(v, time / dtime);
		vadd(v, p->o) if (p->local)
		vadd(v, p.o) if (p.local)
		{
			loopv(players)
			{
				dynent *o = players[i];
				if (!o)
					continue;
				projdamage(o, p, v, i, -1, qdam);
			}
			if (p->owner != player1)
			if (p.owner != player1)
				projdamage(player1, p, v, -1, -1, qdam);
			dvector &mv = getmonsters();
			loopv(mv) if (!vreject(mv[i]->o, v, 10.0f) &&
			    mv[i] != p->owner)
			    mv[i] != p.owner)
			    projdamage(mv[i], p, v, -1, i, qdam);
		}
		if (p->inuse) {
		if (p.inuse) {
			if (time == dtime)
				splash(p, v, p->o, -1, -1, qdam);
				splash(p, v, p.o, -1, -1, qdam);
			else {
				if (p->gun == GUN_RL) {
					dodynlight(p->o, v, 0, 255, p->owner);
				if (p.gun == GUN_RL) {
					dodynlight(p.o, v, 0, 255, p.owner);
					particle_splash(5, 2, 200, v);
				} else {
					particle_splash(1, 1, 200, v);
					particle_splash(
					    guns[p->gun].part, 1, 1, v);
					    guns[p.gun].part, 1, 1, v);
				}
			}
		}
		p->o = v;
		p.o = v;
	}
}

void
shootv(int gun, OFVector3D &from, OFVector3D &to, dynent *d,
    bool local) // create visual effect from a shot
{

Modified src/worldlight.mm from [6a518301f9] to [ccc85287d7].

196
197
198
199
200
201
202
203
204


205
206
207
208
209
210
211
196
197
198
199
200
201
202


203
204
205
206
207
208
209
210
211







-
-
+
+







		block *backup = dlights.pop();
		blockpaste(*backup);
		free(backup);
	}
}

void
dodynlight(
    OFVector3D &vold, OFVector3D &v, int reach, int strength, dynent *owner)
dodynlight(const OFVector3D &vold, const OFVector3D &v, int reach, int strength,
    dynent *owner)
{
	if (!reach)
		reach = dynlight;
	if (owner->monsterstate)
		reach = reach / 2;
	if (!reach)
		return;