Compare commits

...

18 Commits

5
.gitignore vendored

@ -1,3 +1,6 @@
flight*.zip
flight_server
flight.zip
ipsettings.h
.vs/
@ -6,4 +9,4 @@ x64/
*.obj
*.pdb
*.ilk
*.gen.h
*.gen.h

@ -7,12 +7,18 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Flight", "Flight.vcxproj",
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug No Host|x64 = Debug No Host|x64
Debug No Host|x86 = Debug No Host|x86
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5A0EDC10-F875-4CD0-AF1D-CC7E13336AF6}.Debug No Host|x64.ActiveCfg = Debug No Host|x64
{5A0EDC10-F875-4CD0-AF1D-CC7E13336AF6}.Debug No Host|x64.Build.0 = Debug No Host|x64
{5A0EDC10-F875-4CD0-AF1D-CC7E13336AF6}.Debug No Host|x86.ActiveCfg = Debug No Host|Win32
{5A0EDC10-F875-4CD0-AF1D-CC7E13336AF6}.Debug No Host|x86.Build.0 = Debug No Host|Win32
{5A0EDC10-F875-4CD0-AF1D-CC7E13336AF6}.Debug|x64.ActiveCfg = Debug|x64
{5A0EDC10-F875-4CD0-AF1D-CC7E13336AF6}.Debug|x64.Build.0 = Debug|x64
{5A0EDC10-F875-4CD0-AF1D-CC7E13336AF6}.Debug|x86.ActiveCfg = Debug|Win32

@ -1,6 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug No Host|Win32">
<Configuration>Debug No Host</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug No Host|x64">
<Configuration>Debug No Host</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
@ -32,6 +40,12 @@
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug No Host|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
@ -45,6 +59,12 @@
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug No Host|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
@ -60,12 +80,18 @@
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug No Host|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug No Host|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
@ -82,6 +108,18 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug No Host|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
@ -102,7 +140,22 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DEBUG_RENDERING;SERVER_ADDRESS="127.0.0.1"</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>C:\Users\Cameron\Documents\flight\thirdparty\enet\include;C:\Users\Cameron\Documents\flight\thirdparty\Chipmunk2D\include\chipmunk;C:\Users\Cameron\Documents\flight\thirdparty;C:\Users\Cameron\Documents\flight\thirdparty\Chipmunk2D\include;C:\Users\Cameron\Documents\flight\thirdparty\minilzo</AdditionalIncludeDirectories>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies);Ws2_32.lib;winmm.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug No Host|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DEBUG_RENDERING;</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>C:\Users\Cameron\Documents\flight\thirdparty\enet\include;C:\Users\Cameron\Documents\flight\thirdparty\Chipmunk2D\include\chipmunk;C:\Users\Cameron\Documents\flight\thirdparty;C:\Users\Cameron\Documents\flight\thirdparty\Chipmunk2D\include;C:\Users\Cameron\Documents\flight\thirdparty\minilzo</AdditionalIncludeDirectories>
<TreatWarningAsError>true</TreatWarningAsError>
@ -121,12 +174,14 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>C:\Users\Cameron\Documents\flight\thirdparty\enet\include;C:\Users\Cameron\Documents\flight\thirdparty\Chipmunk2D\include\chipmunk;C:\Users\Cameron\Documents\flight\thirdparty;C:\Users\Cameron\Documents\flight\thirdparty\Chipmunk2D\include;C:\Users\Cameron\Documents\flight\thirdparty\minilzo</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies);Ws2_32.lib;winmm.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>

@ -7,4 +7,9 @@
<LocalDebuggerCommandArguments>--serve</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug No Host|x64'">
<LocalDebuggerCommandArguments>
</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>

@ -0,0 +1,3 @@
#!/usr/bin/env bash
gcc -o flight_server -Wall -O2 -Ithirdparty -Ithirdparty/enet/include -Ithirdparty/minilzo -Ithirdparty/Chipmunk2D/include -Ithirdparty/Chipmunk2D/include/chipmunk server_main.c server.c debugdraw.c gamestate.c sokol_impl.c thirdparty/minilzo/minilzo.c thirdparty/enet/*.c thirdparty/Chipmunk2D/src/*.c -lm -lpthread

@ -1,5 +1,7 @@
#ifdef DEBUG_RENDERING
#include "sokol_gfx.h"
#include "sokol_gp.h"
#endif
#include "types.h"
#define MAX_COMMANDS 64
@ -27,30 +29,44 @@ typedef struct Command
// thread local variables so debug drawing in server thread
// doesn't fuck up main thread
static __declspec(thread) Command commands[MAX_COMMANDS] = {0};
static __declspec(thread) int command_i = 0;
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#define THREADLOCAL __declspec(thread)
#else
#define THREADLOCAL __thread
#endif
static THREADLOCAL Command commands[MAX_COMMANDS] = {0};
static THREADLOCAL int command_i = 0;
void dbg_drawall()
{
// return;
#ifdef DEBUG_RENDERING
sgp_set_color(0.4f, 0.8f, 0.2f, 0.8f);
for (int i = 0; i < command_i; i++)
{
const float size = 0.05f;
switch(commands[i].type)
switch (commands[i].type)
{
case rect:
{
case rect:
V2 center = commands[i].center;
V2 upper_left = V2add(center, (V2){.x = -size / 2.0f, .y = -size / 2.0f});
sgp_draw_filled_rect(upper_left.x, upper_left.y, size, size);
break;
case line:
V2 from = commands[i].from;
V2 to = commands[i].to;
sgp_draw_line(from.x, from.y, to.x, to.y);
break;
V2 center = commands[i].center;
V2 upper_left = V2add(center, (V2){.x = -size / 2.0f, .y = -size / 2.0f});
sgp_draw_filled_rect(upper_left.x, upper_left.y, size, size);
break;
}
case line:
{
V2 from = commands[i].from;
V2 to = commands[i].to;
sgp_draw_line(from.x, from.y, to.x, to.y);
break;
}
}
}
#endif
command_i = 0;
}
@ -73,4 +89,4 @@ void dbg_rect(V2 center)
};
command_i++;
command_i %= MAX_COMMANDS;
}
}

@ -0,0 +1,9 @@
[Unit]
Description=Flight
[Service]
ExecStart=/root/flight/flight_server
Restart=always
[Install]
WantedBy=multi-user.target

@ -471,11 +471,18 @@ static cpBool on_damage(cpArbiter* arb, cpSpace* space, cpDataPointer userData)
entity_b = cp_shape_entity(b);
float damage = V2length(cp_to_v2(cpArbiterTotalImpulse(arb))) * COLLISION_DAMAGE_SCALING;
if (entity_a->is_box && entity_a->box_type == BoxExplosive)
entity_a->damage += 2.0f * EXPLOSION_DAMAGE_THRESHOLD;
if (entity_b->is_box && entity_b->box_type == BoxExplosive)
entity_b->damage += 2.0f * EXPLOSION_DAMAGE_THRESHOLD;
if (damage > 0.05f)
{
// Log("Collision with damage %f\n", damage);
entity_a->damage += damage;
entity_b->damage += damage;
}
// b must be the key passed into the post step removed, the key is cast into its shape
@ -515,12 +522,6 @@ V2 grid_com(Entity* grid)
return cp_to_v2(cpBodyLocalToWorld(grid->body, cpBodyGetCenterOfGravity(grid->body)));
}
V2 entity_pos(Entity* e)
{
assert(!e->is_box);
// @Robust merge entity_pos with box_pos
return cp_to_v2(cpBodyGetPosition(e->body));
}
V2 grid_vel(Entity* grid)
{
return cp_to_v2(cpBodyGetVelocity(grid->body));
@ -568,15 +569,20 @@ float entity_shape_mass(Entity* box)
assert(box->shape != NULL);
return (float)cpShapeGetMass(box->shape);
}
V2 box_pos(Entity* box)
{
assert(box->is_box);
return V2add(entity_pos(box_grid(box)), V2rotate(entity_shape_pos(box), entity_rotation(box_grid(box))));
}
float box_rotation(Entity* box)
{
return (float)cpBodyGetAngle(cpShapeGetBody(box->shape));
}
V2 entity_pos(Entity* e)
{
if (e->is_box) {
return V2add(entity_pos(box_grid(e)), V2rotate(entity_shape_pos(e), entity_rotation(box_grid(e))));
}
else {
assert(e->body != NULL);
return cp_to_v2(cpBodyGetPosition(e->body));
}
}
struct BodyData
{
@ -711,6 +717,7 @@ void ser_player(SerState* ser, Player* p)
SER_VAR(&p->connected);
if (p->connected)
{
SER_VAR(&p->unlocked_bombs);
ser_entityid(ser, &p->entity);
ser_inputframe(ser, &p->input);
}
@ -779,6 +786,14 @@ void ser_entity(SerState* ser, GameState* gs, Entity* e)
SER_VAR(&e->goldness);
}
SER_VAR(&e->is_explosion);
if (e->is_explosion)
{
ser_V2(ser, &e->explosion_pos);
ser_V2(ser, &e->explosion_vel);
SER_VAR(&e->explosion_progresss);
}
SER_VAR(&e->is_grid);
if (e->is_grid)
{
@ -790,9 +805,11 @@ void ser_entity(SerState* ser, GameState* gs, Entity* e)
if (e->is_box)
{
SER_VAR(&e->box_type);
SER_VAR(&e->is_explosion_unlock);
ser_entityid(ser, &e->next_box);
ser_entityid(ser, &e->prev_box);
SER_VAR(&e->compass_rotation);
SER_VAR(&e->indestructible);
SER_VAR(&e->thrust);
SER_VAR(&e->wanted_thrust);
SER_VAR(&e->energy_used);
@ -872,7 +889,8 @@ void ser_server_to_client(SerState* ser, ServerToClient* s)
Entity* e = &gs->entities[next_index];
e->exists = true;
ser_entity(ser, gs, e);
gs->cur_next_entity = (unsigned int)max(gs->cur_next_entity, next_index + 1);
unsigned int possible_next_index = (unsigned int)(next_index + 1);
gs->cur_next_entity = gs->cur_next_entity < possible_next_index ? possible_next_index : gs->cur_next_entity;
}
for (size_t i = 0; i < gs->cur_next_entity; i++)
{
@ -955,6 +973,34 @@ Entity* closest_to_point_in_radius(GameState* gs, V2 point, float radius)
return NULL;
}
static float cur_explosion_damage = 0.0f;
static V2 explosion_origin = { 0 };
static void explosion_callback_func(cpShape* shape, cpContactPointSet* points, void* data)
{
GameState* gs = (GameState*)data;
cp_shape_entity(shape)->damage += cur_explosion_damage;
Entity* parent = get_entity(gs, cp_shape_entity(shape)->shape_parent_entity);
V2 from_pos = entity_pos(cp_shape_entity(shape));
V2 impulse = V2scale(V2normalize(V2sub(from_pos, explosion_origin)), EXPLOSION_PUSH_STRENGTH);
assert(parent->body != NULL);
cpBodyApplyImpulseAtWorldPoint(parent->body, v2_to_cp(impulse), v2_to_cp(from_pos));
}
static void do_explosion(GameState* gs, Entity* explosion, float dt)
{
cur_explosion_damage = dt * EXPLOSION_DAMAGE_PER_SEC;
explosion_origin = explosion->explosion_pos;
cpBody* tmpbody = cpBodyNew(0.0f, 0.0f);
cpShape* circle = cpCircleShapeNew(tmpbody, EXPLOSION_RADIUS, v2_to_cp(explosion_origin));
cpSpaceShapeQuery(gs->space, circle, explosion_callback_func, (void*)gs);
cpShapeFree(circle);
cpBodyFree(tmpbody);
}
V2 box_facing_vector(Entity* box)
{
assert(box->is_box);
@ -1002,6 +1048,53 @@ bool possibly_use_energy(GameState* gs, Entity* grid, float wanted_energy)
return false;
}
void entity_ensure_in_orbit(Entity* e)
{
cpVect pos = v2_to_cp(V2sub(entity_pos(e), SUN_POS));
cpFloat r = cpvlength(pos);
cpFloat v = cpfsqrt(SUN_GRAVITY_STRENGTH / r) / r;
cpBodySetVelocity(e->body, cpvmult(cpvperp(pos), v));
}
EntityID create_spacestation(GameState* gs)
{
#define BOX_AT_TYPE(grid, pos, type) { Entity* box = new_entity(gs); box_create(gs, box, grid, pos); box->box_type = type; box->indestructible = indestructible; }
#define BOX_AT(grid, pos) BOX_AT_TYPE(grid, pos, BoxHullpiece)
bool indestructible = false;
Entity* grid = new_entity(gs);
grid_create(gs, grid);
entity_set_pos(grid, (V2) { -150.0f, 0.0f });
entity_ensure_in_orbit(grid);
Entity* explosion_box = new_entity(gs);
box_create(gs, explosion_box, grid, (V2) { 0 });
explosion_box->is_explosion_unlock = true;
BOX_AT_TYPE(grid, ((V2) { BOX_SIZE, 0 }), BoxExplosive);
BOX_AT_TYPE(grid, ((V2) { BOX_SIZE*2, 0 }), BoxHullpiece);
BOX_AT_TYPE(grid, ((V2) { BOX_SIZE*3, 0 }), BoxHullpiece);
BOX_AT_TYPE(grid, ((V2) { BOX_SIZE*4, 0 }), BoxHullpiece);
indestructible = true;
for (float y = -BOX_SIZE * 5.0; y <= BOX_SIZE * 5.0; y += BOX_SIZE)
{
BOX_AT_TYPE(grid, ((V2) { BOX_SIZE*5.0, y }), BoxHullpiece);
}
for (float x = -BOX_SIZE * 5.0; x <= BOX_SIZE * 5.0; x += BOX_SIZE)
{
BOX_AT_TYPE(grid, ((V2) { x, BOX_SIZE*5.0 }), BoxHullpiece);
BOX_AT_TYPE(grid, ((V2) { x, -BOX_SIZE*5.0 }), BoxHullpiece);
}
indestructible = false;
BOX_AT_TYPE(grid, ((V2) { -BOX_SIZE*6.0, BOX_SIZE*5.0 }), BoxExplosive);
BOX_AT_TYPE(grid, ((V2) { -BOX_SIZE*6.0, BOX_SIZE*3.0 }), BoxExplosive);
BOX_AT_TYPE(grid, ((V2) { -BOX_SIZE*6.0, BOX_SIZE*1.0 }), BoxExplosive);
BOX_AT_TYPE(grid, ((V2) { -BOX_SIZE*6.0, -BOX_SIZE*2.0 }), BoxExplosive);
BOX_AT_TYPE(grid, ((V2) { -BOX_SIZE*6.0, -BOX_SIZE*3.0 }), BoxExplosive);
BOX_AT_TYPE(grid, ((V2) { -BOX_SIZE*6.0, -BOX_SIZE*5.0 }), BoxExplosive);
return get_id(gs, grid);
}
void process(GameState* gs, float dt)
{
assert(gs->space != NULL);
@ -1010,26 +1103,20 @@ void process(GameState* gs, float dt)
gs->time += dt;
// process input
for (int i = 0; i < MAX_PLAYERS; i++)
PLAYERS_ITER(gs->players, player)
{
struct Player* player = &gs->players[i];
if (!player->connected)
continue;
Entity* p = get_entity(gs, player->entity);
if (p == NULL)
{
p = new_entity(gs);
create_player(gs, p);
player->entity = get_id(gs, p);
cpVect pos = v2_to_cp(V2sub(entity_pos(p), SUN_POS));
cpFloat r = cpvlength(pos);
cpFloat v = cpfsqrt(SUN_GRAVITY_STRENGTH / r) / r;
cpBodySetVelocity(p->body, cpvmult(cpvperp(pos), v));
entity_ensure_in_orbit(p);
}
assert(p->is_player);
#ifdef INFINITE_RESOURCES
p->spice_taken_away = 0.0f;
p->damage = 0.0f;
#endif
// update gold win condition
if (V2length(V2sub(cp_to_v2(cpBodyGetPosition(p->body)), gs->goldpos)) < GOLD_COLLECT_RADIUS)
@ -1066,7 +1153,7 @@ void process(GameState* gs, float dt)
}
else
{
V2 pilot_seat_exit_spot = V2add(box_pos(the_seat), V2scale(box_facing_vector(the_seat), BOX_SIZE));
V2 pilot_seat_exit_spot = V2add(entity_pos(the_seat), V2scale(box_facing_vector(the_seat), BOX_SIZE));
cpBodySetPosition(p->body, v2_to_cp(pilot_seat_exit_spot));
cpBodySetVelocity(p->body, v2_to_cp(player_vel(gs, p)));
the_seat->player_who_is_inside_of_me = (EntityID){ 0 };
@ -1095,10 +1182,10 @@ void process(GameState* gs, float dt)
{
assert(seat_inside_of->is_box);
cpShapeSetFilter(p->shape, CP_SHAPE_FILTER_NONE); // no collisions while in a seat
cpBodySetPosition(p->body, v2_to_cp(box_pos(seat_inside_of)));
cpBodySetPosition(p->body, v2_to_cp(entity_pos(seat_inside_of)));
// set thruster thrust from movement
if(seat_inside_of->box_type == BoxCockpit) {
if (seat_inside_of->box_type == BoxCockpit) {
Entity* g = get_entity(gs, seat_inside_of->shape_parent_entity);
V2 target_direction = { 0 };
@ -1132,9 +1219,12 @@ void process(GameState* gs, float dt)
if (nearest != NULL)
{
Entity* cur_box = cp_shape_entity(nearest);
Entity* cur_grid = cp_body_entity(cpShapeGetBody(nearest));
p->damage -= DAMAGE_TO_PLAYER_PER_BLOCK*((BATTERY_CAPACITY - cur_box->energy_used)/BATTERY_CAPACITY);
grid_remove_box(gs, cur_grid, cur_box);
if (!cur_box->indestructible)
{
Entity* cur_grid = cp_body_entity(cpShapeGetBody(nearest));
p->damage -= DAMAGE_TO_PLAYER_PER_BLOCK * ((BATTERY_CAPACITY - cur_box->energy_used) / BATTERY_CAPACITY);
grid_remove_box(gs, cur_grid, cur_box);
}
}
else if (target_grid == NULL)
{
@ -1169,17 +1259,34 @@ void process(GameState* gs, float dt)
p->damage = clamp01(p->damage);
}
if(get_entity(gs, gs->cur_spacestation) == NULL)
{
gs->cur_spacestation = create_spacestation(gs);
}
// process entities
for (size_t i = 0; i < gs->cur_next_entity; i++) {
Entity* e = &gs->entities[i];
if (!e->exists)
continue;
if (e->is_explosion_unlock)
{
PLAYERS_ITER(gs->players, player)
{
Entity* player_entity = get_entity(gs, player->entity);
if (player_entity != NULL && V2length(V2sub(entity_pos(player_entity), entity_pos(e))) < GOLD_UNLOCK_RADIUS)
{
player->unlocked_bombs = true;
}
}
}
if (e->body != NULL)
{
cpVect p = cpvsub(cpBodyGetPosition(e->body), v2_to_cp(SUN_POS));
cpFloat sqdist = cpvlengthsq(p);
if(sqdist > (INSTANT_DEATH_DISTANCE_FROM_SUN*INSTANT_DEATH_DISTANCE_FROM_SUN))
if (sqdist > (INSTANT_DEATH_DISTANCE_FROM_SUN * INSTANT_DEATH_DISTANCE_FROM_SUN))
{
entity_destroy(gs, e);
continue;
@ -1194,8 +1301,27 @@ void process(GameState* gs, float dt)
cpBodyUpdateVelocity(e->body, g, 1.0f, dt);
}
if (e->is_explosion)
{
e->explosion_progresss += dt;
e->explosion_pos = V2add(e->explosion_pos, V2scale(e->explosion_vel, dt));
do_explosion(gs, e, dt);
if (e->explosion_progresss >= EXPLOSION_TIME)
{
entity_destroy(gs, e);
}
}
if (e->is_box)
{
if (e->box_type == BoxExplosive && e->damage >= EXPLOSION_DAMAGE_THRESHOLD)
{
Entity* explosion = new_entity(gs);
explosion->is_explosion = true;
explosion->explosion_pos = entity_pos(e);
explosion->explosion_vel = grid_vel(box_grid(e));
grid_remove_box(gs, get_entity(gs, e->shape_parent_entity), e);
}
if (e->damage >= 1.0f)
{
grid_remove_box(gs, get_entity(gs, e->shape_parent_entity), e);
@ -1208,7 +1334,7 @@ void process(GameState* gs, float dt)
BOXES_ITER(gs, cur, e)
{
if (cur->box_type == BoxSolarPanel) {
cur->sun_amount = clamp01(V2dot(box_facing_vector(cur), V2normalize(V2sub(SUN_POS, box_pos(cur)))));
cur->sun_amount = clamp01(V2dot(box_facing_vector(cur), V2normalize(V2sub(SUN_POS, entity_pos(cur)))));
energy_to_add += cur->sun_amount * SOLAR_ENERGY_PER_SECOND * dt;
}
}
@ -1237,7 +1363,7 @@ void process(GameState* gs, float dt)
if (possibly_use_energy(gs, e, energy_to_consume))
{
cur->thrust = cur->wanted_thrust;
cpBodyApplyForceAtWorldPoint(e->body, v2_to_cp(thruster_force(cur)), v2_to_cp(box_pos(cur)));
cpBodyApplyForceAtWorldPoint(e->body, v2_to_cp(thruster_force(cur)), v2_to_cp(entity_pos(cur)));
}
}
if (cur->box_type == BoxMedbay)
@ -1245,7 +1371,7 @@ void process(GameState* gs, float dt)
Entity* potential_meatbag_to_heal = get_entity(gs, cur->player_who_is_inside_of_me);
if (potential_meatbag_to_heal != NULL)
{
float energy_to_recharge = min(potential_meatbag_to_heal->damage, PLAYER_ENERGY_RECHARGE_PER_SECOND * dt);
float energy_to_recharge = fminf(potential_meatbag_to_heal->damage, PLAYER_ENERGY_RECHARGE_PER_SECOND * dt);
if (possibly_use_energy(gs, e, energy_to_recharge))
{
potential_meatbag_to_heal->damage -= energy_to_recharge;

@ -0,0 +1,7 @@
#!/usr/bin/env bash
./build_linux_server_release.sh
cp flight.service /etc/systemd/system/
systemctl enable flight
systemctl start flight
systemctl restart flight

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

112
main.c

@ -54,6 +54,8 @@ static sg_image image_stars;
static sg_image image_stars2;
static sg_image image_sun;
static sg_image image_medbay_used;
static sg_image image_mystery;
static sg_image image_explosion;
static int cur_editing_boxtype = -1;
static int cur_editing_rotation = 0;
@ -61,6 +63,7 @@ static struct BoxInfo {
enum BoxType type;
const char* image_path;
sg_image image;
bool needs_tobe_unlocked;
} boxes[] = {
// if added to here will show up in toolbar, is placeable
{
@ -75,10 +78,6 @@ static struct BoxInfo {
.type = BoxBattery,
.image_path = "loaded/battery.png",
},
{
.type = BoxSolarPanel,
.image_path = "loaded/solarpanel.png",
},
{
.type = BoxCockpit,
.image_path = "loaded/cockpit.png",
@ -87,6 +86,15 @@ static struct BoxInfo {
.type = BoxMedbay,
.image_path = "loaded/medbay.png",
},
{
.type = BoxSolarPanel,
.image_path = "loaded/solarpanel.png",
},
{
.type = BoxExplosive,
.image_path = "loaded/explosive.png",
.needs_tobe_unlocked = true,
},
};
const int boxes_len = sizeof(boxes) / sizeof(*boxes);
@ -171,6 +179,8 @@ init(void)
image_stars2 = load_image("loaded/stars2.png");
image_sun = load_image("loaded/sun.png");
image_medbay_used = load_image("loaded/medbay_used.png");
image_mystery = load_image("loaded/mystery.png");
image_explosion = load_image("loaded/explosion.png");
}
// socket initialization
@ -273,6 +283,22 @@ myentity()
return to_return;
}
bool can_build(int i)
{
bool allow_building = true;
if (boxinfo((enum BoxType)i).needs_tobe_unlocked)
{
allow_building = gs.players[myplayer].unlocked_bombs;
}
return allow_building;
}
void attempt_to_build(int i)
{
if (can_build(i))
cur_editing_boxtype = i;
}
static void
ui(bool draw, float dt, float width, float height)
{
@ -326,8 +352,8 @@ ui(bool draw, float dt, float width, float height)
mouse_pos)
&& mouse_pressed) {
// "handle" mouse pressed
attempt_to_build(i);
mouse_pressed = false;
cur_editing_boxtype = i;
}
if (draw) {
@ -339,7 +365,14 @@ ui(bool draw, float dt, float width, float height)
sgp_set_image(0, image_itemframe);
}
sgp_draw_textured_rect(x, y, itemframe_width, itemframe_height);
sgp_set_image(0, boxinfo((enum BoxType)i).image);
struct BoxInfo info = boxinfo((enum BoxType)i);
if (can_build(i))
{
sgp_set_image(0, info.image);
}
else {
sgp_set_image(0, image_mystery);
}
transform_scope
{
float item_x = x + item_offset_x;
@ -370,8 +403,8 @@ static void draw_dots(V2 camera_pos, float gap)
if (fabsf(star.y - camera_pos.y) > VISION_RADIUS)
continue;
star.x += hash11(star.x * 100.0f + star.y * 67.0f)*gap;
star.y += hash11(star.y * 93.0f + star.x * 53.0f)*gap;
star.x += hash11(star.x * 100.0f + star.y * 67.0f) * gap;
star.y += hash11(star.y * 93.0f + star.x * 53.0f) * gap;
sgp_draw_point(star.x, star.y);
}
}
@ -422,20 +455,21 @@ frame(void)
.cur_gs = &gs,
};
// @Robust @BeforeShip maximum acceptable message size?
char decompressed[MAX_BYTES_SIZE] = { 0 };
size_t decompressed_len = MAX_BYTES_SIZE;
char* decompressed = malloc(sizeof * decompressed * MAX_BYTES_SIZE);
size_t decompressed_max_len = MAX_BYTES_SIZE;
assert(LZO1X_MEM_DECOMPRESS == 0);
int return_value = lzo1x_decompress_safe(event.packet->data, event.packet->dataLength, decompressed, &decompressed_len, NULL);
int return_value = lzo1x_decompress_safe(event.packet->data, event.packet->dataLength, decompressed, &decompressed_max_len, NULL);
// @Robust not sure what return_value is, error test on it somehow
if (return_value == LZO_E_OK)
{
from_bytes(&msg, decompressed, decompressed_len);
from_bytes(&msg, decompressed, decompressed_max_len);
myplayer = msg.your_player;
}
else {
Log("Couldn't decompress gamestate packet, error code %d from lzo\n", return_value);
}
enet_packet_destroy(event.packet);
free(decompressed);
break;
}
@ -576,7 +610,7 @@ frame(void)
ENetPacket* packet = enet_packet_create((void*)&client_to_server,
sizeof(client_to_server),
ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT);
enet_peer_send(peer, 0, packet);
enet_peer_send(peer, 0, packet); // @Robust error check this
last_input_sent_time = time;
}
}
@ -695,19 +729,25 @@ frame(void)
Entity* e = &gs.entities[i];
if (!e->exists)
continue;
if (e->is_grid) // grid drawing
// draw grid
if (e->is_grid)
{
Entity* g = e;
BOXES_ITER(&gs, b, g)
{
if (b->is_explosion_unlock)
{
set_color(colhexcode(0xfcba03));
draw_circle(entity_pos(b), GOLD_UNLOCK_RADIUS);
}
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f);
// debug draw force vectors for thrusters
#if 0
{
if (b->type == BoxThruster)
{
dbg_rect(box_pos(b));
dbg_line(box_pos(b), V2add(box_pos(b), V2scale(thruster_force(b), -1.0f)));
dbg_rect(entity_pos(b));
dbg_line(entity_pos(b), V2add(entity_pos(b), V2scale(thruster_force(b), -1.0f)));
}
}
#endif
@ -715,14 +755,14 @@ frame(void)
float cur_alpha = sgp_get_color().a;
Color from = WHITE;
Color to = colhex(255, 0, 0);
Color result = Collerp(from, to, b->energy_used/BATTERY_CAPACITY);
Color result = Collerp(from, to, b->energy_used / BATTERY_CAPACITY);
sgp_set_color(result.r, result.g, result.b, cur_alpha);
}
transform_scope
{
sgp_rotate_at(entity_rotation(g) + rotangle(b->compass_rotation),
box_pos(b).x,
box_pos(b).y);
entity_pos(b).x,
entity_pos(b).y);
if (b->box_type == BoxThruster) {
transform_scope
@ -735,8 +775,8 @@ frame(void)
// float scaling = 1.1;
// sgp_translate(-(scaling*BOX_SIZE - BOX_SIZE), 0.0);
// sgp_scale(scaling, 1.0);
sgp_scale_at(scaling, 1.0f, box_pos(b).x, box_pos(b).y);
draw_texture_centered(box_pos(b), BOX_SIZE);
sgp_scale_at(scaling, 1.0f, entity_pos(b).x, entity_pos(b).y);
draw_texture_centered(entity_pos(b), BOX_SIZE);
sgp_reset_image(0);
}
}
@ -752,27 +792,33 @@ frame(void)
img = image_medbay_used;
}
sgp_set_image(0, img);
draw_texture_centered(box_pos(b), BOX_SIZE);
if (b->indestructible)
{
sgp_set_color(0.2f, 0.2f, 0.2f, 1.0f);
}
draw_texture_centered(entity_pos(b), BOX_SIZE);
sgp_reset_image(0);
if (b->box_type == BoxSolarPanel)
{
Color to_set = colhexcode(0xeb9834);
to_set.a = b->sun_amount*0.5f;
to_set.a = b->sun_amount * 0.5f;
set_color(to_set);
draw_color_rect_centered(box_pos(b), BOX_SIZE);
draw_color_rect_centered(entity_pos(b), BOX_SIZE);
}
sgp_set_color(0.5f, 0.1f, 0.1f, b->damage);
draw_color_rect_centered(box_pos(b), BOX_SIZE);
draw_color_rect_centered(entity_pos(b), BOX_SIZE);
}
}
// draw the velocity
#if 0
sgp_set_color(1.0f, 0.0f, 0.0f, 1.0f);
V2 vel = grid_vel(g);
V2 to = V2add(grid_com(g), vel);
sgp_draw_line(grid_com(g).x, grid_com(g).y, to.x, to.y);
#endif
}
if (e->is_player && get_entity(&gs, e->currently_inside_of_box) == NULL) {
transform_scope
@ -784,7 +830,15 @@ frame(void)
sgp_reset_image(0);
}
}
if (e->is_explosion)
{
sgp_set_image(0, image_explosion);
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f - (e->explosion_progresss / EXPLOSION_TIME));
draw_texture_centered(e->explosion_pos, EXPLOSION_RADIUS * 2.0f);
sgp_reset_image(0);
}
}
// gold target
set_color(GOLD);
sgp_draw_filled_rect(gs.goldpos.x, gs.goldpos.y, 0.1f, 0.1f);
@ -805,9 +859,9 @@ frame(void)
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f);
dbg_drawall();
} // world space transform end
} // world space transform end
}
}
// UI drawn in screen space
ui(true, dt, width, height);
@ -818,7 +872,7 @@ frame(void)
sgp_end();
sg_end_pass();
sg_commit();
}
}
void cleanup(void)
{
@ -843,7 +897,7 @@ void event(const sapp_event* e)
int key_num = e->key_code - SAPP_KEYCODE_0;
int target_box = key_num - 1;
if (target_box < BoxLast) {
cur_editing_boxtype = target_box;
attempt_to_build(target_box);
}
if (!mouse_frozen) {

@ -21,6 +21,9 @@ void server(void* data)
initialize(&gs, entity_data, entities_size);
Log("Allocated %zu bytes for entities\n", entities_size);
#define BOX_AT_TYPE(grid, pos, type) { Entity* box = new_entity(&gs); box_create(&gs, box, grid, pos); box->box_type = type; }
#define BOX_AT(grid, pos) BOX_AT_TYPE(grid, pos, BoxHullpiece)
// one box policy
if (false)
{
@ -41,12 +44,11 @@ void server(void* data)
cpBodySetVelocity(grid->body, cpv(-0.1, 0.0));
cpBodySetAngularVelocity(grid->body, 1.0f);
#define BOX_AT(pos) { Entity* box = new_entity(&gs); box_create(&gs, box, grid, pos); }
BOX_AT(((V2) { 0 }));
BOX_AT(((V2) { BOX_SIZE, 0 }));
BOX_AT(((V2) { 2.0*BOX_SIZE, 0 }));
BOX_AT(((V2) { 2.0*BOX_SIZE, BOX_SIZE }));
BOX_AT(((V2) { 0.0*BOX_SIZE, -BOX_SIZE }));
BOX_AT(grid,((V2) { 0 }));
BOX_AT(grid,((V2) { BOX_SIZE, 0 }));
BOX_AT(grid,((V2) { 2.0*BOX_SIZE, 0 }));
BOX_AT(grid,((V2) { 2.0*BOX_SIZE, BOX_SIZE }));
BOX_AT(grid,((V2) { 0.0*BOX_SIZE, -BOX_SIZE }));
}
if (enet_initialize() != 0)
@ -122,6 +124,10 @@ void server(void* data)
event.peer->data = (void*)player_slot;
gs.players[player_slot] = (struct Player){ 0 };
gs.players[player_slot].connected = true;
player_to_latest_id_processed[player_slot] = 0;
#ifdef UNLOCK_ALL
gs.players[player_slot].unlocked_bombs = true;
#endif
}
break;
@ -129,9 +135,9 @@ void server(void* data)
case ENET_EVENT_TYPE_RECEIVE:
{
// Log("A packet of length %zu was received on channel %u.\n",
// event.packet->dataLength,
// event.channelID);
//Log("A packet of length %zu was received on channel %u.\n",
// event.packet->dataLength,
//event.channelID);
size_t length = event.packet->dataLength;
if (length != sizeof(struct ClientToServer))
@ -188,6 +194,11 @@ void server(void* data)
{
int player_index = (int)(int64_t)event.peer->data;
Log("%" PRId64 " disconnected player index %d.\n", (int64_t)event.peer->data, player_index);
Entity* player_body = get_entity(&gs, gs.players[player_index].entity);
if(player_body != NULL)
{
entity_destroy(&gs, player_body);
}
gs.players[player_index].connected = false;
// box_destroy(&gs.players[player_index].box);
event.peer->data = NULL;
@ -214,13 +225,13 @@ void server(void* data)
static char lzo_working_mem[LZO1X_1_MEM_COMPRESS] = { 0 };
for (int i = 0; i < server->peerCount; i++)
{
static char bytes_buffer[MAX_BYTES_SIZE] = { 0 };
static char compressed_buffer[MAX_BYTES_SIZE] = { 0 };
// @Speed don't recreate the packet for every peer, gets expensive copying gamestate over and over again
if (server->peers[i].state != ENET_PEER_STATE_CONNECTED)
{
continue;
}
// @Speed don't recreate the packet for every peer, gets expensive copying gamestate over and over again
char* bytes_buffer = malloc(sizeof *bytes_buffer * MAX_BYTES_SIZE);
char* compressed_buffer = malloc(sizeof * compressed_buffer * MAX_BYTES_SIZE);
struct ServerToClient to_send;
to_send.cur_gs = &gs;
to_send.your_player = (int)(int64_t)server->peers[i].data;
@ -237,7 +248,15 @@ void server(void* data)
#endif
//ENetPacket* gamestate_packet = enet_packet_create((void*)bytes_buffer, len, ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT);
ENetPacket* gamestate_packet = enet_packet_create((void*)compressed_buffer, compressed_len, ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT);
enet_peer_send(&server->peers[i], 0, gamestate_packet);
// @Robust error check this
int err = enet_peer_send(&server->peers[i], 0, gamestate_packet);
if (err < 0)
{
Log("Enet failed to send packet error %d\n", err);
enet_packet_destroy(gamestate_packet);
}
free(bytes_buffer);
free(compressed_buffer);
}
}
}

@ -0,0 +1,10 @@
#include "types.h"
#define SOKOL_IMPL
#include "sokol_time.h"
int main(int argc, char **argv)
{
server(0);
return 0;
}

@ -1,30 +1,36 @@
#pragma once
#define MAX_PLAYERS 4
#define MAX_ENTITIES 1024
#define MAX_PLAYERS 8
#define MAX_ENTITIES 1024*2
#define BOX_SIZE 0.25f
#define PLAYER_SIZE ((V2){.x = BOX_SIZE, .y = BOX_SIZE})
#define PLAYER_MASS 0.5f
#define PLAYER_JETPACK_FORCE 2.0f
//#define PLAYER_JETPACK_SPICE_PER_SECOND 0.3f
#define PLAYER_JETPACK_SPICE_PER_SECOND 0.0f
#define PLAYER_JETPACK_FORCE 1.5f
// #define PLAYER_JETPACK_FORCE 20.0f
#define PLAYER_JETPACK_SPICE_PER_SECOND 0.1f
#define MAX_HAND_REACH 1.0f
#define GOLD_COLLECT_RADIUS 0.3f
#define BUILD_BOX_SNAP_DIST_TO_SHIP 0.2f
#define BOX_MASS 1.0f
#define COLLISION_DAMAGE_SCALING 0.1f
#define THRUSTER_FORCE 4.0f
#define THRUSTER_ENERGY_USED_PER_SECOND 0.05f
#define COLLISION_DAMAGE_SCALING 0.15f
#define THRUSTER_FORCE 12.0f
#define THRUSTER_ENERGY_USED_PER_SECOND 0.005f
#define VISION_RADIUS 16.0f
#define MAX_BYTES_SIZE 1024 * 8 // maximum size of gamestate buffer
#define MAX_BYTES_SIZE 1024 * 128 // maximum size of serialized gamestate buffer
#define SUN_RADIUS 10.0f
#define INSTANT_DEATH_DISTANCE_FROM_SUN 300.0f
#define INSTANT_DEATH_DISTANCE_FROM_SUN 500.0f
#define SUN_POS ((V2){50.0f,0.0f})
#define SUN_GRAVITY_STRENGTH (5.0e3f)
#define SUN_GRAVITY_STRENGTH (9.0e2f)
#define SOLAR_ENERGY_PER_SECOND 0.02f
#define DAMAGE_TO_PLAYER_PER_BLOCK 0.1f
#define BATTERY_CAPACITY DAMAGE_TO_PLAYER_PER_BLOCK
#define BATTERY_CAPACITY DAMAGE_TO_PLAYER_PER_BLOCK*0.7f
#define PLAYER_ENERGY_RECHARGE_PER_SECOND 0.1f
#define EXPLOSION_TIME 0.5f
#define EXPLOSION_PUSH_STRENGTH 5.0f
#define EXPLOSION_DAMAGE_PER_SEC 10.0f
#define EXPLOSION_RADIUS 1.0f
#define EXPLOSION_DAMAGE_THRESHOLD 0.2f // how much damage until it explodes
#define GOLD_UNLOCK_RADIUS 1.0f
#define TIMESTEP (1.0f / 60.0f) // not required to simulate at this, but this defines what tick the game is on
#define TIME_BETWEEN_INPUT_PACKETS (1.0f / 20.0f)
@ -86,6 +92,7 @@ enum BoxType
BoxCockpit,
BoxMedbay,
BoxSolarPanel,
BoxExplosive,
BoxLast,
};
@ -150,6 +157,12 @@ typedef struct Entity
EntityID currently_inside_of_box;
float goldness; // how much the player is a winner
// explosion
bool is_explosion;
V2 explosion_pos;
V2 explosion_vel;
float explosion_progresss; // in seconds
// grids
bool is_grid;
float total_energy_capacity;
@ -158,9 +171,11 @@ typedef struct Entity
// boxes
bool is_box;
enum BoxType box_type;
bool is_explosion_unlock;
EntityID next_box;
EntityID prev_box; // doubly linked so can remove in middle of chain
enum CompassRotation compass_rotation;
bool indestructible;
float wanted_thrust; // the thrust command applied to the thruster
float thrust; // the actual thrust it can provide based on energy sources in the grid
float energy_used; // battery
@ -171,6 +186,7 @@ typedef struct Entity
typedef struct Player
{
bool connected;
bool unlocked_bombs;
EntityID entity;
InputFrame input;
} Player;
@ -185,6 +201,8 @@ typedef struct GameState
Player players[MAX_PLAYERS];
EntityID cur_spacestation;
// Entity arena
// ent:ity pointers can't move around because of how the physics engine handles user data.
// if you really need this, potentially refactor to store entity IDs instead of pointers
@ -195,6 +213,8 @@ typedef struct GameState
EntityID free_list;
} GameState;
#define PLAYERS_ITER(players, cur) for(Player * cur = players; cur < players+MAX_PLAYERS; cur++) if(cur->connected)
#define PI 3.14159f
// returns in radians
@ -236,6 +256,7 @@ struct ClientToServer
void server(void* data); // data parameter required from thread api...
// gamestate
EntityID create_spacestation(GameState* gs);
void initialize(struct GameState* gs, void* entity_arena, size_t entity_arena_size);
void destroy(struct GameState* gs);
void process(struct GameState* gs, float dt); // does in place
@ -252,6 +273,8 @@ V2 entity_pos(Entity* e);
void entity_set_rotation(Entity* e, float rot);
void entity_set_pos(Entity* e, V2 pos);
float entity_rotation(Entity* e);
void entity_ensure_in_orbit(Entity* e);
void entity_destroy(GameState* gs, Entity* e);
#define BOX_CHAIN_ITER(gs, cur, starting_box) for (Entity *cur = get_entity(gs, starting_box); cur != NULL; cur = get_entity(gs, cur->next_box))
#define BOXES_ITER(gs, cur, grid_entity_ptr) BOX_CHAIN_ITER(gs, cur, (grid_entity_ptr)->boxes)
@ -269,7 +292,6 @@ V2 grid_world_to_local(Entity* grid, V2 world);
V2 grid_snapped_box_pos(Entity* grid, V2 world); // returns the snapped pos in world coords
float entity_angular_velocity(Entity* grid);
V2 entity_shape_pos(Entity* box);
V2 box_pos(Entity* box); // returns in world coords
float box_rotation(Entity* box);
// thruster

Loading…
Cancel
Save