/*
This file is part of Minitrem.
Minitrem is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Minitrem is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Minitrem. If not, see .
*/
#include "game.hpp"
namespace game {
size_t selection_cookie = 1;
entity_t::entity_t(game::state_t *game_, int type_) : world::entity_t(type_)
{
game = game_;
}
entity_t::~entity_t(void)
{
}
void entity_t::destroy(void)
{
unlink();
game->awake_entities.erase(this);
delete this;
}
void entity_t::place(world::world_t *world_)
{
bool do_spawn = false;
if (!world)
do_spawn = true;
link(world_);
if (do_spawn)
on_spawn();
if (!ignore_waking)
wake();
}
void entity_t::place(world::world_t *world, v2f_t x_)
{
x = x_;
cmodel.bounds = size + x;
render_bounds = render_size + x;
place(world);
}
void entity_t::wake(void)
{
awake = true;
wake_time = game->now;
game->awake_entities.insert(this);
if (!ignore_waking)
on_wake();
}
void entity_t::sleep(void)
{
awake = false;
game->awake_entities.erase(this);
}
void state_t::start(void)
{
unit_soldier_t *soldier;
world.generator = worldgen;
world.generator_data = (void*)this;
soldier = new unit_soldier_t(this);
soldier->place(&world, v2f_t(0.5, 0.5));
soldier = new unit_soldier_t(this);
soldier->place(&world, v2f_t(1.5, 0.5));
soldier = new unit_soldier_t(this);
soldier->place(&world, v2f_t(2.5, 0.5));
select(rectf_t(v2f_t(0.5, 0.5), v2f_t(2.5, 0.5)));
resume();
}
void state_t::stop(void)
{
}
void state_t::group_say(std::string text)
{
interface->print(text::get(text::SAY_GROUP) + ": " + text);
}
void state_t::select(rectf_t x)
{
selection_cookie++;
selected_units.clear();
for (world::entity_t *ent : world.get_render_entities(x)) {
unit_t *unit;
if (ent->type != ET_UNIT)
continue;
unit = (unit_t*)ent;
if (!unit->controllable)
continue;
unit->selected = selection_cookie;
selected_units.insert(unit);
}
if (selected_units.size() == 1)
(*selected_units.begin())->say(text::get(text::SAY_READY));
else if (selected_units.size() > 1)
group_say(text::get(text::SAY_READY_GROUP));
}
void state_t::command(v2f_t x)
{
v2f_t snap;
snap[0] = std::round(x[0] - 0.5f) + 0.5f;
snap[1] = std::round(x[1] - 0.5f) + 0.5f;
if (selected_units.size() > 1)
group_say(text::get(text::SAY_MOVING_GROUP));
for (unit_t *unit : selected_units) {
unit_soldier_t *soldier;
if (unit->type != unit_t::UNIT_SOLDIER)
continue;
soldier = dynamic_cast(unit);
if (soldier->dead)
continue;
if (!soldier->controllable)
continue;
if (!soldier->start_moving(snap))
soldier->say(text::get(text::SAY_NO_PATH));
else {
soldier->move_marker = std::make_unique(this, soldier->move.path.back());
if (selected_units.size() == 1)
soldier->say(text::get(text::SAY_MOVING));
}
}
}
void state_t::spawn_soldier(v2f_t x)
{
unit_soldier_t *soldier;
world::cmodel_t cmodel;
soldier = new unit_soldier_t(this);
soldier->place(&world, x);
cmodel.bounds = soldier->cmodel.bounds;
cmodel.cflags = soldier->move.cflags;
if (world.test_rect(&cmodel, soldier))
soldier->destroy();
}
void state_t::pause(void)
{
paused = true;
}
void state_t::resume(void)
{
t0 = nclock();
frames_since_t0 = 0;
paused = false;
}
#define TIME_DELTA ((ntime_t)1000000000 / 60)
void state_t::tick(ntime_t time_)
{
size_t target, frames_this_tick = 0;
if (paused)
return;
target = (time_ - t0) / TIME_DELTA;
while (frames_since_t0 < target) {
// FIXME: Is this non-deterministic enough?
dice_prng.seed(dice_prng.next() ^ time);
// setting up old variables (refactor them out eventually)
now = time * 1.0e-9;
dt = TIME_DELTA * 1.0e-9;
// on_think can insert/erase elements of awake_entities so iterate
// over a copy of it.
auto copy = awake_entities;
for (entity_t *ent : copy)
ent->on_think();
frames++;
frames_since_t0++;
frames_this_tick++;
time += TIME_DELTA;
if (frames_this_tick == 3) {
t0 = time_;
frames_since_t0 = 0;
frames_behind++;
break;
}
}
}
die_t::die_t(size_t sides_)
{
sides = sides_;
}
die_t::die_t(size_t count_, size_t sides_)
{
count = count_;
sides = sides_;
}
die_t::die_t(size_t count_, size_t sides_, size_t bonus_)
{
count = count_;
sides = sides_;
bonus = bonus_;
}
size_t state_t::roll(die_t die)
{
size_t total = 0;
for (size_t i = 0; i < die.count; i++)
total += dice_prng.next() % die.sides + 1;
return total + die.bonus;
}
bool load_assets(void)
{
assets::load();
return true;
}
} //namespace game