summaryrefslogtreecommitdiff
path: root/kon/konworld.h
blob: cccab2f463ed4c1c7736d2b2ad197af28608c024 (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
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
/* SPDX-License-Identifier: MIT */
/*
 * konworld.h
 *
 * Copyright (c) 2026 KonAki
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef KONWORLD_H
#define KONWORLD_H

#include "konmath.h"
#include "kontile.h"
#include "kon3d.h"
#include "konsector.h"

#ifdef __cplusplus
extern "C" {
#endif

/*** definition ***/

/* one place to ask "can I stand here, can I walk there" for everything a 3d game is built from: the rooms of a sector map,
   a terrain, a tilemap, and any shapes you add yourself. x and z are the plan, y is up. a world only points at the maps and the
   terrain, they stay yours and can change between frames. nothing here knows what a door or a monster is, a door is a box that
   the game moves */

#define KON_NO_GROUND (-1.0e30f)

typedef enum kon_colliderType {
	KON_COLLIDER_NONE = 0,
	KON_COLLIDER_BOX,      /* min and max, sides line up with the axes */
	KON_COLLIDER_CYLINDER, /* standing on the ground, center is the middle of its bottom */
	KON_COLLIDER_SPHERE,   /* blocks only, you can't stand on one */
	KON_COLLIDER_PLANE     /* everything behind the plane is solid. a plane that faces mostly up is a floor, a ramp if it is tilted */
} kon_colliderType_t;

typedef struct kon_collider {
	int type;
	int enabled; /* 0 and it is ignored, 1 */
	int user;    /* yours, like the entity this belongs to */
	kon_vec3_t min, max;       /* box */
	kon_vec3_t center;         /* cylinder, sphere */
	float radius, height;      /* cylinder, sphere (no height) */
	kon_vec3_t normal;         /* plane, the side it faces, length 1. points p with dot(normal, p) < offset are solid */
	float offset;
} kon_collider_t;

kon_collider_t kon_colliderBox(kon_vec3_t min, kon_vec3_t max);
kon_collider_t kon_colliderCylinder(kon_vec3_t bottom, float radius, float height);
kon_collider_t kon_colliderSphere(kon_vec3_t center, float radius);
kon_collider_t kon_colliderPlane(kon_vec3_t point, kon_vec3_t normal);

typedef struct kon_world {
	const kon_sectorMap_t *sectors;  /* any of these three can be NULL */
	const kon_terrain_t *terrain;
	const kon_tilemap_t *tiles;      /* one unit per tile like the rest of kon3d */
	const uint8_t *solid;            /* indexed by tile id like kon_tilemapMove */
	int solidCount;
	float tileHeight;                /* how tall the solid tiles are, 1 */

	kon_collider_t *colliders;
	int colliderCount, colliderCap;

	float gravity;   /* 20 */
	float stepHeight; /* the biggest step you walk up without jumping, 0.35 */
	float maxSlope;  /* rise over run you can climb on terrain, 1 is 45 degrees */
} kon_world_t;

/* a thing that walks. position is where the feet are, the body is a cylinder going up from there */
typedef struct kon_body {
	kon_vec3_t position;
	float radius, height; /* 0.2 and 1.0 are fine for a person in this scale */
	float vy;             /* up speed, only jumps and falls change it */
	float jumpSpeed;      /* how fast a jump starts, 6 is about a metre. 0 turns jumping off for this body, like in a doom-style game */
	int onGround;
	int sector;           /* the room it is in, -1 if none, kept up to date by kon_worldMove */
	int touching;         /* the collider it was pushed by in the last move, -1 if none. a monster hitting a door, say */
} kon_body_t;

/*** the world ***/

void kon_worldInit(kon_world_t *world);
void kon_worldFree(kon_world_t *world);

/* returns the index, or -1 if there is no memory. the index stays the same until the collider is removed */
int kon_worldAdd(kon_world_t *world, kon_collider_t collider);

/* NULL if the index is not a collider. change it any time, a door opens by raising min.y */
kon_collider_t *kon_worldCollider(kon_world_t *world, int index);
void kon_worldRemove(kon_world_t *world, int index);

/* the height of the highest thing to stand on at x, z that is not more than a step above feet, or KON_NO_GROUND outside the world.
   hint is the sector you were in, -1 if you have none. sector gets the room the point is in, it can be NULL */
float kon_worldGround(const kon_world_t *world, float x, float z, float feet, int hint, int *sector);

/*** bodies ***/

void kon_bodyInit(kon_body_t *body, float x, float y, float z, float radius, float height);
/* does nothing in the air or when jumpSpeed is 0. returns 1 if it jumped */
int kon_bodyJump(kon_body_t *body);

/* puts the feet on the ground under them right away */
void kon_worldPlace(const kon_world_t *world, kon_body_t *body);

/* moves by dx, dz and slides along whatever is in the way: walls, shapes, steps that are too high, slopes that are too steep, the edge
   of the world. then gravity: steps up are taken at once and drops are falls. dt is seconds */
void kon_worldMove(kon_world_t *world, kon_body_t *body, float dx, float dz, double dt);

/*** rays ***/

typedef enum kon_hitKind {
	KON_HIT_NONE = 0,
	KON_HIT_WALL,     /* a wall of a sector, or the step or lintel of an opening */
	KON_HIT_FLOOR,
	KON_HIT_CEILING,
	KON_HIT_COLLIDER,
	KON_HIT_TERRAIN,
	KON_HIT_TILE
} kon_hitKind_t;

typedef struct kon_rayHit {
	int kind;
	float distance;
	kon_vec3_t point, normal; /* normal faces back at the ray */
	int sector;   /* the room a wall, floor or ceiling belongs to, -1 for the rest */
	int edge;     /* which wall of that room, -1 for the rest */
	int collider; /* the index, -1 for the rest */
} kon_rayHit_t;

/* shoots a ray and finds the first thing it hits within maxDistance. direction does not have to be 1 long. hit can be NULL.
   a ray through the rooms of a sector map has to start inside one. shapes the ray starts inside are not hit */
int kon_worldRay(const kon_world_t *world, kon_vec3_t origin, kon_vec3_t direction, float maxDistance, kon_rayHit_t *hit);

/* 1 if nothing is between the two points. for "can the monster see me" and "is the light reaching here" */
int kon_worldVisible(const kon_world_t *world, kon_vec3_t from, kon_vec3_t to);


#ifdef __cplusplus
}
#endif
#endif