aboutsummaryrefslogtreecommitdiff
path: root/src/bullets.c
blob: ea913c76fb124a6cb2151c0a5bc8534b86032755 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include "bullets.h"
#include "game.h"

Bullet createBulletFromEntity(Entity entity, float damage) {
	return (Bullet){
		.ray = (Ray){
			entity.position,
			Vector3RotateByQuaternion((Vector3){0.0, 0.0, 1.0}, entity.rotation)
		},
		.fromId = entity.id,
		.fromFingerprint = entity.fingerprint,
		.damage = damage
	};
}

BulletHitInfo handleBulletHit(Entity * entity, Bullet bullet) {
	// Handle health.
	entity->health -= bullet.damage;
	entity->health = Clamp(entity->health, ENTITY_MIN_HEALTH, ENTITY_MAX_HEALTH);

	// Check hit info.
	BulletHitInfo hitInfo = (BulletHitInfo){
		.hit = true,
		.killed = entity->health == 0.0,
		.hitId = entity->id,
		.hitFingerprint = entity->fingerprint
	};

	return hitInfo;
}

BulletHitInfo shootBullet(World * world, Bullet bullet) {
	int i, j;
	RayCollision collision;
	Entity * currentEntity;
	Ray ray;

	// Set direction.
	ray.direction = bullet.ray.direction;

	// Stores all the hits so we can find closest one.
	int hits[world->entitiesCount];
	size_t hitsSize = 0;

	// Loop through entities.
	for (i = 0; i < world->entitiesCount; ++i) {
		currentEntity = &world->entities[i];

		// This was the entity that shot it.
		if (currentEntity->fingerprint == bullet.fromFingerprint)
			continue;
		else if (currentEntity->model == NULL) // Null model indeed.
			continue;

		// Set position relative to entity.
		ray.position = Vector3Subtract(bullet.ray.position, currentEntity->position);

		// Loop through meshes.
		for (j = 0; j < currentEntity->model->meshCount; ++j) {
			collision = GetRayCollisionMesh(
				ray,
				currentEntity->model->meshes[j],
				currentEntity->model->transform
			);

			// Did hit.
			if (collision.hit) {
				hits[hitsSize] = i;
				++hitsSize;
				break;
			}
		}
	}

	// No hits.
	if (hitsSize == 0)
		return (BulletHitInfo){
			.hit = false,
			.killed = false,
			.hitId = ENTITY_NONE,
		};

	float dis = Vector3Distance(world->entities[hits[0]].position, bullet.ray.position);
	float closest = dis;
	int closestNum = 0;

	// Find closest.
	for (i = 0; i < hitsSize; ++i) {
		dis = Vector3Distance(world->entities[hits[i]].position, bullet.ray.position);

		// This fucker is closer.
		if (dis < closest) {
			closest = dis;
			closestNum = i;
		}
	}

	// Handle closest bullet.
	return handleBulletHit(&world->entities[hits[closestNum]], bullet);
}