summaryrefslogtreecommitdiff
path: root/src/entity.c
blob: 58f3c9dc0f514be6f0b65f5556d0c95592d3c236 (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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "entity.h"
#include "entitytag.h"
#include "map.h"
#include "game.h"
#include <stdio.h>
#include <string.h>

static void
_points(Entity *this, int ox, int oy, int *x0, int *x1, int *y0, int *y1)
{
	*x0 = this->pos[0] - this->width / 2 + ox;
	*y0 = this->pos[1] - this->width / 2 + oy;
	*x1 = *x0 + this->width - 1;
	*y1 = *y0 + this->height - 1;
}

unsigned int
entity_type(const char *typename)
{
	if (typename == NULL)
		return 0;
	for (unsigned i = 0; i < num_entitytags; i++)
		if (strcmp(typename, entitytags[i].name) == 0)
			return i + 1;
	printf("unknown type '%s'\n", typename);
	return 0;
}

unsigned int
entity_type_parent(unsigned int type)
{
	if (type == 0)
		return 0;
	if (entitytags[type - 1].parent != NULL)
		return entity_type(entitytags[type - 1].parent);
	return 0;
}

bool
entity_is_type(unsigned int type, unsigned int search)
{
	do {
		if (type == search)
			return true;
		type = entity_type_parent(type);
	} while (type != 0);
	return false;
}

bool
entity_collide(Entity *this, int ox, int oy)
{
	int x0, y0, x1, y1;
	_points(this, ox, oy, &x0, &x1, &y0, &y1);
	return (map_get_px(x0, y0) == 1 || map_get_px(x0, y1) == 1 ||
	        map_get_px(x1, y0) == 1 || map_get_px(x1, y1) == 1);
}

bool
entity_meet(Entity *this, Entity *other)
{
	int tx0, ty0, tx1, ty1;
	int ox0, oy0, ox1, oy1;
	_points(this, 0, 0, &tx0, &tx1, &ty0, &ty1);
	_points(other, 0, 0, &ox0, &ox1, &oy0, &oy1);
	return (tx0 < ox1 && tx1 > ox0 && ty0 < oy1 && ty1 > oy0);
}

Entity *
entity_place_meeting(Entity *this, struct Game *g, unsigned int type)
{
	for (__auto_type i = MAX_ENTITIES - 1; i >= 0; i--)
		if (this != &g->entities[i] &&
		    entity_is_type(g->entities[i].type, type) &&
		    entity_meet(this, &g->entities[i]))
			return &g->entities[i];
	return NULL;
}

void
entity_move(Entity *this, [[maybe_unused]] struct Game *g)
{
	if (this->ignore_solids) {
		for (int a = 0; a < 2; a++) {
			const double sum = this->vel[a] + this->rem[a];
			int spd = (int)sum;
			this->rem[a] = sum - spd;
			this->pos[a] += spd;
		}
		return;
	}
	if (entity_collide(this, 0, 0)) {
		this->vel[0] = 0.0;
		this->vel[1] = 0.0;
		this->rem[0] = 0.0;
		this->rem[1] = 0.0;
		return;
	}
	for (int a = 0; a < 2; a++) {
		const double sum = this->vel[a] + this->rem[a];
		int spd = (int)sum;
		this->rem[a] = sum - spd;
		const int sign = (spd > 0) - (spd < 0);
		if (sign == 0)
			continue;
		while (spd != 0) {
			this->pos[a] += sign;
			if (entity_collide(this, 0, 0)) {
				this->pos[a] -= sign;
				this->rem[a] = 0.0;
				this->vel[a] = 0.0;
				break;
			}
			spd -= sign;
		}
	}
}

Entity *
entity_init(Entity *this, unsigned int type, const char *name, int x, int y,
            int w, int h)
{
	entitytags[type - 1].init(this, name, x, y, w, h);
	return this;
}