add ranged magic attack with auto-aim on scepter in lv2
This commit is contained in:
parent
1b75c9353d
commit
a84592b280
|
@ -6,4 +6,6 @@ player_spawn: 5,1
|
|||
spawner: 5,4
|
||||
spawner: 18,5
|
||||
|
||||
wave: 10s 4*slime/1
|
||||
item: scepter1
|
||||
wave: 20s 40*slime/1
|
||||
|
|
14
src/aoe.c
14
src/aoe.c
|
@ -53,7 +53,7 @@ entity_t *aoe_make_attack(uint16_t type, entity_t *origin, vec2 dir)
|
|||
anim = &anims_skill_hit;
|
||||
hitbox = (rect){ -fix(4)/16, fix(3)/16, -fix(4)/16, fix(3)/16 };
|
||||
}
|
||||
else if(type == AOE_PROJECTILE) {
|
||||
else if(type == AOE_PROJECTILE || type == AOE_PROJECTILE_FAST) {
|
||||
anim = &anims_skill_projectile;
|
||||
hitbox = (rect){ -fix(1)/16, fix(1)/16, -fix(1)/16, fix(1)/16 };
|
||||
distance = fix(0.5);
|
||||
|
@ -121,10 +121,13 @@ entity_t *aoe_make_attack(uint16_t type, entity_t *origin, vec2 dir)
|
|||
aoe->data.generic.strength = f->MAG;
|
||||
aoe->data.generic.dir = p->facing;
|
||||
}
|
||||
else if(type == AOE_PROJECTILE) {
|
||||
else if(type == AOE_PROJECTILE || type == AOE_PROJECTILE_FAST) {
|
||||
aoe->data.projectile.strength = f->ATK;
|
||||
aoe->data.projectile.direction = dir;
|
||||
aoe->data.projectile.speed = fix(3.0);
|
||||
if(type == AOE_PROJECTILE_FAST)
|
||||
aoe->data.projectile.speed = fix(6.0);
|
||||
else
|
||||
aoe->data.projectile.speed = fix(3.0);
|
||||
p->facing = (dir.x >= 0 ? RIGHT : LEFT);
|
||||
v->z = fix(0.5);
|
||||
v->shadow_size = 3;
|
||||
|
@ -207,7 +210,7 @@ static bool attack_apply(game_t *game, aoe_t *aoe, entity_t *target)
|
|||
dir = fdir(aoe->data.generic.dir);
|
||||
damage = aoe->data.generic.strength;
|
||||
}
|
||||
else if(aoe->type == AOE_PROJECTILE) {
|
||||
else if(aoe->type == AOE_PROJECTILE || aoe->type == AOE_PROJECTILE_FAST) {
|
||||
dir = aoe->data.projectile.direction;
|
||||
damage = aoe->data.projectile.strength;
|
||||
r /= 2;
|
||||
|
@ -281,6 +284,7 @@ void aoe_apply(game_t *game, entity_t *entity, entity_t *e)
|
|||
|
||||
if(aoe->type == AOE_HIT
|
||||
|| aoe->type == AOE_PROJECTILE
|
||||
|| aoe->type == AOE_PROJECTILE_FAST
|
||||
|| aoe->type == AOE_SLASH
|
||||
|| aoe->type == AOE_IMPALE
|
||||
|| aoe->type == AOE_SHOCK
|
||||
|
@ -318,7 +322,7 @@ void aoe_update(game_t *game, entity_t *entity, fixed_t dt)
|
|||
physical_t *p = getcomp(entity, physical);
|
||||
aoe_t *aoe = getcomp(entity, aoe);
|
||||
|
||||
if(aoe->type == AOE_PROJECTILE) {
|
||||
if(aoe->type == AOE_PROJECTILE || aoe->type == AOE_PROJECTILE_FAST) {
|
||||
fixed_t v = aoe->data.projectile.speed;
|
||||
p->x += fmul(fmul(aoe->data.projectile.direction.x, v), dt);
|
||||
p->y += fmul(fmul(aoe->data.projectile.direction.y, v), dt);
|
||||
|
|
|
@ -15,6 +15,7 @@ enum {
|
|||
AOE_HIT,
|
||||
/* Simple ranged attack */
|
||||
AOE_PROJECTILE,
|
||||
AOE_PROJECTILE_FAST,
|
||||
/* Normal attack by a slashing weapon */
|
||||
AOE_SLASH,
|
||||
/* Impaling attack using a slashing weapon */
|
||||
|
@ -58,7 +59,7 @@ typedef struct
|
|||
struct { int type; } item;
|
||||
/* Generic attacks: source and ATK strength */
|
||||
struct { int strength; int dir; } generic;
|
||||
/* AOE_PROJECTILE: speed and direction of movement */
|
||||
/* AOE_PROJECTILE, AOE_PROJECTILE_FAST: speed and direction */
|
||||
struct { int strength; vec2 direction; fixed_t speed; } projectile;
|
||||
/* AOE_SHOCK: origin and ATK strength */
|
||||
struct { int strength; vec2 origin; } shock;
|
||||
|
|
|
@ -30,6 +30,23 @@ vec2 vec_i2f_center(ivec2 p)
|
|||
return (vec2){ fix(p.x) + fix(0.5), fix(p.y) + fix(0.5) };
|
||||
}
|
||||
|
||||
fixed_t vec_dot(vec2 v, vec2 u)
|
||||
{
|
||||
return fmul(v.x, u.x) + fmul(v.y, u.y);
|
||||
}
|
||||
|
||||
vec2 vec_rotate_30(vec2 v)
|
||||
{
|
||||
return (vec2){ fmul(fix(0.866), v.x) - v.y / 2,
|
||||
v.x / 2 + fmul(fix(0.866), v.y) };
|
||||
}
|
||||
|
||||
vec2 vec_rotate_m30(vec2 v)
|
||||
{
|
||||
return (vec2){ fmul(fix(0.866), v.x) + v.y / 2,
|
||||
-v.x / 2 + fmul(fix(0.866), v.y) };
|
||||
}
|
||||
|
||||
//---
|
||||
// Rect operations
|
||||
//---
|
||||
|
|
|
@ -55,6 +55,14 @@ vec2 vec_i2f_center(ivec2);
|
|||
ivec2 vec_f2i(vec2);
|
||||
irect rect_f2i(rect);
|
||||
|
||||
/* Dot product. */
|
||||
fixed_t vec_dot(vec2, vec2);
|
||||
|
||||
/* Rotate a vector by 30° */
|
||||
vec2 vec_rotate_30(vec2);
|
||||
/* Rotate a vector by -30° */
|
||||
vec2 vec_rotate_m30(vec2);
|
||||
|
||||
//---
|
||||
// Point operations
|
||||
//---
|
||||
|
|
|
@ -204,11 +204,11 @@ void item_skills(int item, int *skill1, int *skill2, int *skill3)
|
|||
*skill2 = AOE_SHOCK;
|
||||
}
|
||||
if(item == ITEM_SCEPTER1) {
|
||||
*skill1 = AOE_SLASH; // TODO: Base ranged attack
|
||||
*skill1 = AOE_PROJECTILE_FAST;
|
||||
*skill2 = AOE_JUDGEMENT;
|
||||
}
|
||||
if(item == ITEM_SCEPTER2) {
|
||||
*skill1 = AOE_SLASH;
|
||||
*skill1 = AOE_PROJECTILE_FAST;
|
||||
*skill2 = AOE_JUDGEMENT;
|
||||
*skill3 = AOE_BULLET;
|
||||
}
|
||||
|
|
43
src/main.c
43
src/main.c
|
@ -126,6 +126,7 @@ int main(void)
|
|||
player_f->player = &player_data;
|
||||
for(int i = 0; i < 6; i++)
|
||||
player_f->skills[i] = -1;
|
||||
player_f->skills[0] = AOE_SLASH;
|
||||
for(int i = 0; i < 6; i++)
|
||||
player_f->actions_cooldown[i] = fix(0.0);
|
||||
/* Initialize stats. This will level up to level 1 */
|
||||
|
@ -368,6 +369,11 @@ int main(void)
|
|||
player_f->skills[2] = AOE_JUDGEMENT;
|
||||
player_f->skills[3] = SKILL_DASH;
|
||||
player_f->skills[4] = AOE_BULLET;
|
||||
|
||||
player_data.inventory[4] = ITEM_SWORD1;
|
||||
player_data.inventory[5] = ITEM_SWORD2;
|
||||
player_data.inventory[6] = ITEM_SCEPTER1;
|
||||
player_data.inventory[7] = ITEM_SCEPTER2;
|
||||
}
|
||||
if(ev.key == KEY_F5 && debug.dev_menu)
|
||||
debug.show_perf ^= 1;
|
||||
|
@ -553,23 +559,32 @@ int main(void)
|
|||
/* Player attack */
|
||||
if(!debug.paused && !game.menu_open && player_f->HP > 0 && attack
|
||||
&& !player_f->current_attack) {
|
||||
int hit_number=0, effect=AOE_SLASH;
|
||||
if(player_f->skills[0] == AOE_SLASH) {
|
||||
int hit_number=0, effect=AOE_SLASH;
|
||||
|
||||
/* If hitting within .25s of the previous hit ending, combo! */
|
||||
if(abs(player_f->combo_delay) < fix(0.25))
|
||||
hit_number = player_f->combo_next;
|
||||
player_f->combo_next = (hit_number + 1) % player_f->combo_length;
|
||||
/* If hitting within .25s of the previous hit ending, combo! */
|
||||
if(abs(player_f->combo_delay) < fix(0.25))
|
||||
hit_number = player_f->combo_next;
|
||||
player_f->combo_next = (hit_number+1) % player_f->combo_length;
|
||||
|
||||
if(hit_number == 0) effect = AOE_SLASH;
|
||||
if(hit_number == 1) effect = AOE_IMPALE;
|
||||
entity_t *aoe = aoe_make_attack_4(effect, player,player_p->facing);
|
||||
getcomp(aoe, visible)->z = fix(0.25);
|
||||
game_add_entity(&game, aoe);
|
||||
if(hit_number == 0) effect = AOE_SLASH;
|
||||
if(hit_number == 1) effect = AOE_IMPALE;
|
||||
entity_t *aoe = aoe_make_attack_4(effect, player,
|
||||
player_p->facing);
|
||||
getcomp(aoe, visible)->z = fix(0.25);
|
||||
game_add_entity(&game, aoe);
|
||||
|
||||
visible_set_anim(player, &anims_player_Attack, 2);
|
||||
player_f->current_attack = aoe;
|
||||
player_f->attack_follows_movement = true;
|
||||
player_f->combo_delay = getcomp(aoe, aoe)->lifetime;
|
||||
visible_set_anim(player, &anims_player_Attack, 2);
|
||||
player_f->current_attack = aoe;
|
||||
player_f->attack_follows_movement = true;
|
||||
player_f->combo_delay = getcomp(aoe, aoe)->lifetime;
|
||||
}
|
||||
else if(player_f->skills[0] == AOE_PROJECTILE_FAST) {
|
||||
vec2 dir = pathfinding_autoaim(&game, player, game.map);
|
||||
if(dir.x == 0 && dir.y == 0)
|
||||
dir = fdir(player_p->facing);
|
||||
skill_use(&game, player, 0, dir);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ideas for additional skills:
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#include "pathfinding.h"
|
||||
#include "game.h"
|
||||
#include "util.h"
|
||||
#include "comp/physical.h"
|
||||
#include "comp/fighter.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -316,3 +319,43 @@ vec2 pfc_shortcut_one(pfg_path_t const *grid, vec2 start, vec2 end,
|
|||
|
||||
return target;
|
||||
}
|
||||
|
||||
//---
|
||||
// Auto-aiming
|
||||
//---
|
||||
|
||||
vec2 pathfinding_autoaim(game_t const *game, entity_t *src, map_t const *map)
|
||||
{
|
||||
physical_t *src_p = getcomp(src, physical);
|
||||
if(!src_p)
|
||||
return (vec2){ 0, 0 };
|
||||
|
||||
vec2 src_pos = { src_p->x, src_p->y };
|
||||
vec2 src_facing = fdir(src_p->facing);
|
||||
|
||||
vec2 current_best_dir = { 0, 0 };
|
||||
fixed_t best_dist2 = -1;
|
||||
|
||||
for(int i = 0; i < game->entity_count; i++) {
|
||||
entity_t *e = game->entities[i];
|
||||
physical_t *p = getcomp(e, physical);
|
||||
fighter_t *f = getcomp(e, fighter);
|
||||
if(!p || !f || !f->enemy)
|
||||
continue;
|
||||
|
||||
vec2 relpos = { p->x - src_pos.x, p->y - src_pos.y };
|
||||
if(vec_dot(relpos, vec_rotate_30(src_facing)) < 0)
|
||||
continue;
|
||||
if(vec_dot(relpos, vec_rotate_m30(src_facing)) < 0)
|
||||
continue;
|
||||
|
||||
fixed_t dist2 = fmul(relpos.x, relpos.x) + fmul(relpos.y, relpos.y);
|
||||
if(dist2 < best_dist2 || best_dist2 < 0) {
|
||||
/* TODO: Prune based on raycasts */
|
||||
best_dist2 = dist2;
|
||||
current_best_dir = fnormalize(relpos);
|
||||
}
|
||||
}
|
||||
|
||||
return current_best_dir;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "map.h"
|
||||
#include "geometry.h"
|
||||
#include "comp/entity.h"
|
||||
|
||||
//---
|
||||
// Pathfinding on the grid (pfg)
|
||||
|
@ -136,6 +137,9 @@ vec2 pfc_shortcut_one(pfg_path_t const *path, vec2 start,
|
|||
vec2 end, rect hitbox);
|
||||
|
||||
//---
|
||||
// Auto-aiming
|
||||
//---
|
||||
|
||||
vec2 *pathfind(map_t const *map, vec2 start, vec2 end, int *count,
|
||||
ivec2 **p_grid, int *p_grid_length, rect hitbox);
|
||||
struct game;
|
||||
vec2 pathfinding_autoaim(struct game const *game, entity_t *origin,
|
||||
map_t const *map);
|
||||
|
|
15
src/skills.c
15
src/skills.c
|
@ -14,6 +14,8 @@ fixed_t skill_cooldown(int skill)
|
|||
return fix(5.0);
|
||||
else if(skill == AOE_PROJECTILE)
|
||||
return fix(2.0);
|
||||
else if(skill == AOE_PROJECTILE_FAST)
|
||||
return fix(0.18);
|
||||
else if(skill == AOE_SHOCK)
|
||||
return fix(6.0);
|
||||
else if(skill == AOE_JUDGEMENT)
|
||||
|
@ -52,6 +54,19 @@ bool skill_use(game_t *game, entity_t *e, int slot, vec2 dir)
|
|||
else
|
||||
visible_set_anim(e, f->enemy->id->anim_attack, 2);
|
||||
}
|
||||
else if(skill == AOE_PROJECTILE_FAST) {
|
||||
if(f->current_attack)
|
||||
return false;
|
||||
entity_t *aoe = aoe_make_attack(AOE_PROJECTILE_FAST, e, dir);
|
||||
|
||||
getcomp(aoe, visible)->z = fix(0.25);
|
||||
game_add_entity(game, aoe);
|
||||
|
||||
if(!f->enemy)
|
||||
visible_set_anim(e, &anims_player_Attack, 2);
|
||||
else
|
||||
visible_set_anim(e, f->enemy->id->anim_attack, 2);
|
||||
}
|
||||
else if(skill == AOE_SHOCK) {
|
||||
if(f->current_attack)
|
||||
return false;
|
||||
|
|
|
@ -13,6 +13,7 @@ enum {
|
|||
|
||||
/* Other skills in the AOE enumeration that are valid here: */
|
||||
// AOE_PROJECTILE,
|
||||
// AOE_PROJECTILE_FAST,
|
||||
// AOE_SHOCK,
|
||||
// AOE_JUDGEMENT,
|
||||
// AOE_BULLET,
|
||||
|
|
Loading…
Reference in New Issue