/include/fighter.h (8a155def016c18ebda7e02a6584d74e5e58fbe92) (4811 bytes) (mode 100755) (type blob)
#ifndef FIGHTER_H
#define FIGHTER_H
#ifndef FWORLD_H
#error Include fworld.h before fighter.h so the world can be referenced.
#endif
#include <stdio.h>
#include <cmath>
#include <cstdlib>
#include <functional>
#include <vector>
namespace fighter {
struct Fighter {
size_t entity_index;
int minimum_health;
};
fworld::Entity* FindTarget(
fworld::World* world,
fworld::Entity &entity,
bool attacking );
fworld::Entity* GetMeleeTarget(
fworld::World* world,
fworld::Entity &entity );
void AI(
std::vector<Fighter>* fighters,
fworld::World* world,
unsigned int rand_seed,
double d );
std::vector<Fighter> GetFighters( fworld::World* world );
fworld::Entity* FindTarget(
fworld::World* world,
fworld::Entity &entity,
bool attacking ){
// Make a list of targets.
std::vector<fworld::Entity*> targets;
for( auto &e : world->entities ){
long long tile_x = e.x + 0.5, tile_y = e.y + 0.5;
if( ( attacking
? ( e.type == "spawn" || e.type == "player" )
: ( e.type == "base" )
) && !world->entitiesBumping( entity, e )
&& !world->tileBlocking( tile_x, tile_y, true )
&& world->reachable( (long long)( entity.x + 0.5 ), (long long)( entity.y + 0.5 ), tile_x, tile_y, 15, true ) ){
targets.push_back( &e );
}
}
if( targets.size() > 0 ){
// Randomly pick a target. TODO: Attack the weakest.
return targets[(double)std::rand() / RAND_MAX * targets.size()];
}
return nullptr;
}
fworld::Entity* GetMeleeTarget(
fworld::World* world,
fworld::Entity &entity ){
// Make a list of targets.
std::vector<fworld::Entity*> targets;
for( auto &e : world->entities ){
if( ( e.type == "spawn" || e.type == "player" )
&& world->entitiesBumping( entity, e ) ){
targets.push_back( &e );
}
}
if( targets.size() > 0 ){
// Randomly pick a target. TODO: Attack the weakest.
return targets[(double)std::rand() / RAND_MAX * targets.size()];
}
return nullptr;
}
void AI(
std::vector<Fighter>* fighters,
fworld::World* world,
unsigned int rand_seed,
double d,
std::function<void(fworld::Entity*,fworld::Entity*,int)> hit_callback ){
std::srand( rand_seed );
// Perform AI logic on all of the fighters.
for( auto &f : *fighters ){
if( f.entity_index >= world->entities.size()
|| world->entities[f.entity_index].type != "fighter" ){
// Entity misalignment. Reassign fighters.
// The less this happens, the better. TODO
#ifndef __EMSCRIPTEN__
//fprintf( stderr, "Fighters misaligned. Correcting.\n" );
#endif
*fighters = GetFighters( world );
return;
}
auto &ent = world->entities[f.entity_index];
double patience = 0.1;
// Check if the entity can get a hit in on a player.
fworld::Entity *target = GetMeleeTarget( world, ent );
if( target ){
// Face the target.
world->entityLookAt( ent, *target );
// Only attack if not stunned.
if( ent.stun <= 0.0 ){
ent.task = fworld::TASK_MELEE;
ent.stun = ent.meleeRecovery;
ent.frame = 0.0;
target->health -= ent.meleeDamage;
// Call the callback, where sounds and blood can be handled.
hit_callback( &ent, target, ent.meleeDamage );
}
}
if( ent.task == fworld::TASK_MELEE ){
if( ent.stun <= 0.0 ){
// Stop melee and reset boredom.
ent.task = fworld::TASK_NONE;
ent.boredom = patience;
}
}else if( ent.task == fworld::TASK_NONE
|| ent.path.size() == 0 ){
// Entity is standing still away from the player.
ent.task = fworld::TASK_NONE;
ent.boredom += d;
if( ent.boredom >= patience ){
ent.boredom = 0.0;
// If the entity has sufficient health, find a player
// for it to attack. If the entity does not have
// sufficient health or no player is in range, find a
// base instead.
bool attacking = ent.health >= f.minimum_health;
target = FindTarget( world, ent, attacking );
if( attacking && !target ){
attacking = false;
target = FindTarget( world, ent, attacking );
}
if( target ){
// Keep all paths open if attacking.
if( !attacking )
ent.task = fworld::TASK_BUMP;
world->solveEntityPath(
ent,
(long long)( target->x + 0.5 ),
(long long)( target->y + 0.5 ),
true
);
}
}
}
// Stop the entity's walking animation if not walking or fighting.
if( ent.path.size() == 0 && ent.task != fworld::TASK_MELEE ){
ent.walking = false;
ent.frame = 0.0;
}
}
}
std::vector<Fighter> GetFighters( fworld::World* world ){
std::vector<Fighter> fighters;
for( size_t i = 0; i < world->entities.size(); i++ ){
auto &ent = world->entities[i];
if( ent.type == "fighter" ){
Fighter f = {};
f.entity_index = i;
f.minimum_health = 20;
ent.task = fworld::TASK_NONE;
fighters.push_back( f );
}
}
return fighters;
}
} // namespace fighter
#endif // FIGHTER_H
Mode |
Type |
Size |
Ref |
File |
100644 |
blob |
98 |
227abf3bfa53b2530dcc74495da7bd0ccdcb0775 |
.gitignore |
100644 |
blob |
225 |
9b00c2c2e7b4f0c1e338fdead65f17ba0af089c1 |
COPYING |
100755 |
blob |
43 |
45aea818a4a3202b2467509f28a481cce08834d2 |
Confectioner.command |
100644 |
blob |
14015 |
649b7f0c112c3ac13287bfe88b949fec50356e4d |
Makefile |
100644 |
blob |
2723 |
b5a3f573f076ef740ca742ec9598043732e10c0e |
README.md |
040000 |
tree |
- |
6b3a1677d07517c1f83769dd7675fe6bb9d7a269 |
base |
100755 |
blob |
156 |
84cb1387849f2ca98e53e43536d00af2dfabf7d3 |
caveconfec |
100755 |
blob |
28 |
41b0ef285892c86306eaa269f366dd04cb633d21 |
caveconfec.bat |
100644 |
blob |
198037 |
a0180394c9bf29c02b7ef05916bd5573e3f37da2 |
confec.cpp |
100644 |
blob |
487269 |
29cfd3578eb40b1f039e271bcaa81af49d1b7f3c |
gamecontrollerdb.txt |
040000 |
tree |
- |
62e9d686bbab52d3d88886390b437a3ecef315de |
include |
100755 |
blob |
12081 |
ad29f012941aedfd4ee7232ed95fb68c8c5244c9 |
index-template.html |
100755 |
blob |
1065 |
a460e3c74b8fa53a6f609944ef7e41558479e73f |
libs.cpp |
100755 |
blob |
27581 |
8350a63e947e8a4a55608fd090d128fef7b969a1 |
micropather.cpp |
100644 |
blob |
141235 |
f54e2d2631a628876a631456c043b77da5db78bd |
openjdk.pem |
100755 |
blob |
8 |
e9a74187b02a27b165dfa4f93bf6f060376d0ee6 |
steam_appid.txt |
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"
Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/mse/ConfectionerEngine
Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/mse/ConfectionerEngine
Clone this repository using git:
git clone git://git.rocketgit.com/user/mse/ConfectionerEngine
You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a
merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main