Mentions légales du service

Skip to content
Snippets Groups Projects
Commit f520bf9f authored by PRATS Tommy's avatar PRATS Tommy
Browse files

try to collect main before change engine

parents 052e0370 74635cb0
No related branches found
No related tags found
4 merge requests!131Testing merge against main, to verify CI,!97Engines have test and no leak of memory,!95Enhance Makefile,!94auto export python path when running make tests
Showing
with 1686 additions and 435 deletions
......@@ -2,21 +2,14 @@
from level.level_abc import AbstractLevel
from level.action import Action
from loader.loader import load_level, run_level, test_level
from level.objects import find_map
from utils import cus
import graphic.constants as cst
class Level(AbstractLevel):
def arcade_custom_first_start(self):
knights = [self.map.named_objects[f"knight_{i}"] for i in range(1,7)]
self.last_knight_update = False
self.scattered_knights = False
for i in range(6):
knights[i].visible = True
knights[i].send_update()
knights = [self.map.named_objects[f"knight{i+1}"] for i in range(6)]
cus.debug(f"knights objects: {knights}")
def set_knight_position(i):
......@@ -27,7 +20,6 @@ class Level(AbstractLevel):
frames = memory["stack"]
old_x = knight.coord_x
old_y = knight.coord_y
cus.debug(f"Old knight {i+1} coords : {old_x, old_y}")
map = find_map(frames)
if map is not None and map.tiles[0] != None:
......@@ -42,29 +34,11 @@ class Level(AbstractLevel):
knight.coord_y = y
count += 1
if not self.scattered_knights and (knight.coord_x != old_x or knight.coord_y != old_y or self.last_knight_update):
cus.debug(f"New position for {knight} : {knight.coord_x, knight.coord_y}")
knight._far_move = 'pathfind'
if knight.coord_x != old_x or knight.coord_y != old_y:
cus.debug(f"New position for {knight}")
pl = knight.payload()
pl['action'] = Action('hit')
knight.send_update(pl) # send "hit" payload
knight.send_update() # send "move" payload
if i < 3:
knight.direction = cst.Direction.DOWN
else:
knight.direction = cst.Direction.UP
knight.send_update()
# flag update so the knights don't keep getting hit after they have moved away
if self.last_knight_update:
self.last_knight_update = False
if i == 4:
# we're updating the 5th knight here so we need the 6th next
# (and the 6th doesn't move in the process so it's the only way to update it !)
self.last_knight_update = True
elif i == 5:
# setting a flag here to avoid entering the whole if condition
# again after the knights have scattered away
self.scattered_knights = True
knight.send_update(pl)
return set_knight_position_internal
......@@ -87,11 +61,8 @@ class Level(AbstractLevel):
pl['action'] = Action('hit')
player.send_update(pl)
self.register_breakpoint("knock_back", player_knock_back)
def arcade_custom_restart(self):
self.arcade_custom_first_start()
self.register_breakpoint("knock_back", player_knock_back)
def pre_validation(self):
self.checker.append_inputs(
......
#!/usr/bin/env python3
from level.level_abc import AbstractLevel
from lib.loader.loader import load_level, run_level, test_level
from lib.level.objects import find_var_in_frame, get_top_map
from lib.utils import lvl
import graphic.constants as cst
import arcade
class Level(AbstractLevel):
"""avoid_monster"""
def reset_skeletons(self):
skeletons = [self.map.named_objects[f"skeleton_{i}"] for i in range(1,5)]
for skeleton in skeletons:
payload = {
"topic": "object_update",
"object_name": skeleton.name,
"action": "change_color",
"color": arcade.color.WHITE,
}
self.send_to_gui(payload)
skeleton.visible = False
skeleton.send_update()
def arcade_custom_restart(self):
wop = self.map.named_objects["wop"]
wop.place_at(6, 6)
wop.visible = True
wop.send_update()
self.reset_skeletons()
if self.door_open:
payload = {
"topic": "sprites",
"action": "hide",
"layer": "decorations",
"locations": [
(1, 5), (1, 4)
],
}
self.send_to_gui(payload)
self.door_open = False
def arcade_custom_first_start(self):
player = self.map.player
self.current_map = "main"
skeletons = [self.map.named_objects[f"skeleton_{i}"] for i in range(1,5)]
wop = self.map.named_objects["wop"]
self.door_open = False
self.wop_spawn = False
def change_map(map_name):
self.reset_skeletons()
self.current_map = map_name
payload = {
"topic": "map_change",
"map": map_name,
}
player.send_update(payload)
def detect_map_change():
if wop.visible:
wop.visible = False
wop.send_update()
map_name = "third_room"
if self.current_map == "main":
map_name = "second_room"
change_map(map_name)
def to_direction(direction):
if direction == "DIR_UP":
return cst.Direction.UP
elif direction == "DIR_DOWN":
return cst.Direction.DOWN
elif direction == "DIR_LEFT":
return cst.Direction.LEFT
elif direction == "DIR_RIGHT":
return cst.Direction.RIGHT
def post_update(player, memory):
if not self.wop_spawn:
wop.visible = True
wop.place_at(6, 6)
wop.direction = cst.Direction.LEFT
wop.send_update()
wop.place_at(5, 6)
wop.send_update()
wop.talk("intro")
wop.direction = cst.Direction.RIGHT
wop.place_at(6, 6)
wop.send_update()
wop.direction = cst.Direction.DOWN
wop.send_update()
self.wop_spawn = True
if not self.door_open:
payload = {
"topic": "sprites",
"action": "hide",
"layer": "decorations",
"locations": [
(1, 5), (1, 4)
],
}
self.send_to_gui(payload)
self.door_open = True
frames = memory["stack"]
for frame in frames:
if frame.name == "main":
monsters = find_var_in_frame(frame, "monsters_data")
try:
for m in monsters[0].info:
if m.id != -1:
skeletons[m.id].visible = True
skeletons[m.id].direction = to_direction(m.dir)
skeletons[m.id].place_at(m.x, m.y)
skeletons[m.id].send_update()
if m.player_seen:
payload = {
"topic": "object_update",
"object_name": f"skeleton_{m.id+1}",
"action": "change_color",
"color": arcade.color.RED,
}
self.send_to_gui(payload)
else:
skeletons[m.id].visible = False
skeletons[m.id].send_update()
except:
pass
player.post_update = post_update
self.register_breakpoint("change_map", detect_map_change)
def pre_validation(self):
self.checker.append_inputs(
[
"LEFT",
"LEFT",
"UP",
"WAIT",
"WAIT",
"WAIT",
"WAIT",
"WAIT",
"WAIT",
"WAIT",
"WAIT",
"WAIT",
"WAIT",
"UP",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"UP",
"UP",
"UP",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"DOWN",
"DOWN",
"DOWN",
"DOWN",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"RIGHT",
"DOWN",
"DOWN",
"WAIT",
"WAIT",
"WAIT",
"WAIT",
"DOWN",
"UP",
"DOWN",
"DOWN",
"DOWN",
"LEFT",
"LEFT",
"LEFT",
"LEFT",
"LEFT",
"LEFT",
"LEFT",
"LEFT",
"LEFT",
"LEFT",
"LEFT",
]
)
def test(self):
pass
if __name__ == "__main__":
# run_level(Level, __file__, level_type="text")
# run_level(Level, __file__, level_type="arcade")
test_level(Level, __file__)
\ No newline at end of file
#include "custom_map.h"
#include "input_manager.h"
const char *str_map1 =
"\
+---------------+\n\
|M @|\n\
| |\n\
| |\n\
| |\n\
| M|\n\
| ^ |\n\
| M @|\n\
| M |\n\
| M |\n\
| M |\n\
| --------------|\n\
| >| | | | |\n\
+---------------+\n\
";
//5 UP 9 RIGHT
//5 UP 12 RIGHT
const char *str_map2 =
......@@ -34,27 +35,72 @@ const char *str_map3 = // the monster can move two tiles for 1 movement of the p
"\
+---------------+\n\
| |\n\
|M| |v |\n\
| +-+ |\n\
|M| > |\n\
| | |\n\
| |\n\
| | | |\n\
| +-+ |\n\
| |\n\
+--@------------+\n\
| @ |\n\
+---------------+\n\
";
// initialize the monster : first stat : the id second : direction (for the first map)
void init_map(map * m){
int nb_monster = 0;
for (int y = 0; y<m->height; y++){
// initialize the monsters : first stat : id, direction and coordinates
monsters* init_monsters(map * m, monsters* monsters_data){
monsters_data->length = 0;
for (int y = 0; y < m->height; y++)
{
for(int x = 0; x<m->width; x++){
int i = coord_idx(y,x);
if (m->entities[i] && m->entities[i]->category == MONSTER){
m->entities[i]->stats = malloc(sizeof(int) * 2);
m->entities[i]->stats[0] = nb_monster;
m->entities[i]->stats[1] = 0;
nb_monster++;
if (m->tiles[y][x] == 'M') {;
monsters_data->info[monsters_data->length].id = monsters_data->length;
monsters_data->info[monsters_data->length].dir = DIR_DOWN;
monsters_data->info[monsters_data->length].x = x;
monsters_data->info[monsters_data->length].y = y;
monsters_data->info[monsters_data->length].player_seen = false;
monsters_data->length++;
}
}
}
for (int i = monsters_data->length; i < MAX_MONSTERS; i++)
{
monsters_data->info[i].id = -1;
}
return monsters_data;
}
void show_map(map *m) {
for (int y = 0; y < m->height; y++)
{
for(int x = 0; x<m->width; x++){
printf("%c", m->tiles[y][x]);
}
printf("\n");
}
}
void update_monster(monsters* mon, map* m, int fy, int fx, int ty, int tx) {
if (m->tiles[fy][fx] == 'M' && can_move_to(m, fy, fx, ty, tx)) {
move_without_check(m, fy, fx, ty, tx);
int id = search_monster(mon, m, fy, fx);
if (fx < tx)
mon->info[id].dir = DIR_RIGHT;
else if (fx>tx)
mon->info[id].dir = DIR_LEFT;
else if (fy<ty)
mon->info[id].dir = DIR_DOWN;
else
mon->info[id].dir = DIR_UP;
mon->info[id].x = tx;
mon->info[id].y = ty;
}
}
void verify_monster(game_instance* game, monsters* mon) {
map *m = current_map(game->map_stack);
if (m->tiles[m->player_y][m->player_x] == 'M') {
message("A monster catches you !");
exit(EXIT_FAILURE);
}
}
\ No newline at end of file
#ifndef CUSTOM_MAP_H
#define CUSTOM_MAP_H
#include "../../engines/fullgame/agdbentures.h"
#define MAX_MONSTERS 4
#include "engine/agdbentures.h"
extern const char * str_map1;
extern const char * str_map2;
extern const char * str_map3;
void init_map(map * m);
typedef struct monster_s {
int id;
int x;
int y;
direction dir;
bool player_seen;
} monster;
typedef struct monsters_s {
monster info[MAX_MONSTERS];
int length;
} monsters;
monsters* init_monsters(map *m, monsters* monsters_data);
void show_map(map *m);
void update_monster(monsters *mon, map *m, int fy, int fx, int ty, int tx);
void verify_monster(game_instance* game, monsters* mon);
#endif // CUSTOM_MAP_H
LEFT
LEFT
UP
WAIT
WAIT
WAIT
WAIT
WAIT
WAIT
WAIT
WAIT
WAIT
WAIT
UP
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
UP
UP
UP
RIGHT
RIGHT
RIGHT
RIGHT
DOWN
DOWN
DOWN
DOWN
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
RIGHT
DOWN
DOWN
WAIT
WAIT
WAIT
WAIT
DOWN
UP
DOWN
DOWN
DOWN
LEFT
LEFT
LEFT
LEFT
LEFT
LEFT
LEFT
LEFT
LEFT
LEFT
LEFT
\ No newline at end of file
#include "events_map.h"
int defeat = 0;
int win = 0;
// verify if the player is on the flag
void verify_exit(void) {
map * m = current_map();
if (find_in_stack(m->player_y, m->player_x, FLAG) && defeat!=1) {
printf("You reached the exit!\n");
level_success();
win = 1;
}
}
// verify if a monster is on the same tile as the player
void verify_monster(void){
map * m = current_map();
if (find_in_stack(m->player_y, m->player_x, MONSTER)){
printf("The monster catches you!\n");
level_failed();
defeat = 1;
}
}
\ No newline at end of file
#ifndef EVENTS_MAP_H
#define EVENTS_MAP_H
#include "../../engines/fullgame/agdbentures.h"
#include "custom_map.h"
void verify_exit(void);
void verify_monster(void);
#endif // EVENTS_MAP_H
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.8" tiledversion="1.8.0" orientation="orthogonal" renderorder="right-down" width="20" height="10" tilewidth="32" tileheight="32" infinite="0" backgroundcolor="#000000" nextlayerid="5" nextobjectid="11">
<tileset firstgid="1" source="../../../resources/tiles/[Base]BaseChip_pipo.json"/>
<tileset firstgid="1065" source="../../../resources/tiles/[A]Grass_pipo.json"/>
<tileset firstgid="1593" source="../../../resources/tiles/[A]Water_pipo.json"/>
<layer id="1" name="floor" width="20" height="10">
<data encoding="csv">
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
</data>
</layer>
<layer id="2" name="decorations" width="20" height="10">
<data encoding="csv">
326,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
326,0,0,0,0,0,0,0,0,0,0,0,0,0,0,336,0,0,2814,2815,
326,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
326,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
326,552,0,0,551,0,0,551,0,0,551,0,0,551,0,0,0,0,2814,2815,
326,560,554,558,559,554,558,559,554,558,559,554,558,559,554,558,0,0,2814,2815,
326,0,0,874,0,0,874,0,725,874,961,0,874,0,0,874,0,0,2814,2815,
326,326,326,326,326,326,326,326,326,0,0,0,0,0,0,0,0,0,2814,2815,
326,326,326,326,326,326,326,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,2814,2815
</data>
</layer>
<layer id="3" name="walls" width="20" height="10">
<data encoding="csv">
449,458,458,458,458,458,458,458,458,458,458,458,458,458,458,458,451,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
449,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,451,556,0,0,
457,458,458,458,458,458,458,458,458,458,458,458,458,458,458,458,459,556,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,0,0
</data>
</layer>
<layer id="3" name="decorations_top" width="20" height="10">
<data encoding="csv">
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,551,546,550,552,546,550,552,546,550,552,546,550,552,546,550,0,0,0,0,
0,559,0,0,560,0,0,560,0,0,560,0,0,560,0,0,0,0,0,0,
0,0,0,556,0,0,556,0,1003,556,1055,0,556,0,0,556,0,0,0,0,
0,455,455,455,455,455,455,455,455,455,455,455,455,455,455,455,0,0,0,0,
909,908,0,0,0,0,0,925,925,925,0,0,0,0,0,908,909,0,0,0,
917,916,0,0,0,0,0,933,933,933,0,0,0,0,0,916,917,0,0,0
</data>
</layer>
<objectgroup id="4" name="objects"/>
</map>
......@@ -15,197 +15,247 @@ int in_list(int value, int *list, int len){
}
// apply the movement from (y,x) and to direction d1 first then d2 if possible.
void make_move(int y, int x, direction d1, direction d2){
void make_move(monsters* mon, map* m, int y, int x, direction d1, direction d2){
int y1=y, x1=x;
switch (d1){
case UP: y1 = y-1; break;
case DOWN: y1 = y+1; break;
case RIGHT: x1 = x+1; break;
case LEFT: x1 = x-1; break;
default : break;
switch (d1)
{
case DIR_UP:
y1 = y - 1;
break;
case DIR_DOWN:
y1 = y + 1;
break;
case DIR_RIGHT:
x1 = x + 1;
break;
case DIR_LEFT:
x1 = x - 1;
break;
default:
break;
}
int y2=y1, x2=x1;
switch (d2){
case UP: y2 = y1-1; break;
case DOWN: y2 = y1+1; break;
case RIGHT: x2 = x1+1; break;
case LEFT: x2 = x1-1; break;
case DIR_UP: y2 = y1-1; break;
case DIR_DOWN: y2 = y1+1; break;
case DIR_RIGHT: x2 = x1+1; break;
case DIR_LEFT: x2 = x1-1; break;
default : break;
}
move_entity(y,x,y1,x1);
apply_events();
if (!defeat && d2 != UNKNOWN){
move_entity(y1,x1,y2,x2);
update_monster(mon,m,y,x,y1,x1);
//apply_events(game);
if (d2 != DIR_UNKNOWN){
update_monster(mon,m,y1,x1,y2,x2);
}
}
// verify if a move is possible and apply it if so
int ok_move(int y, int x, direction d1, direction d2){
int y1=y, x1=x;
int ok_move(monsters* mon, map* m, int y, int x, direction d1, direction d2){
int y1 = y, x1 = x;
switch (d1){
case UP: y1 = y-1; break;
case DOWN: y1 = y+1; break;
case RIGHT: x1 = x+1; break;
case LEFT: x1 = x-1; break;
case DIR_UP: y1 = y-1; break;
case DIR_DOWN: y1 = y+1; break;
case DIR_RIGHT: x1 = x+1; break;
case DIR_LEFT: x1 = x-1; break;
default : break;
}
int y2=y1, x2=x1;
switch (d2){
case UP: y2 = y1-1; break;
case DOWN: y2 = y1+1; break;
case RIGHT: x2 = x1+1; break;
case LEFT: x2 = x1-1; break;
case DIR_UP: y2 = y1-1; break;
case DIR_DOWN: y2 = y1+1; break;
case DIR_RIGHT: x2 = x1+1; break;
case DIR_LEFT: x2 = x1-1; break;
default : break;
}
if (d2 == UNKNOWN){
if (!is_obstacle(y1, x1)){
make_move(y,x,d1,d2);
if (d2 == DIR_UNKNOWN){
if (!is_obstacle(m->tiles[y1][x1])){
make_move(mon,m,y,x,d1,d2);
return 1;
}
} else if (!is_obstacle(y1, x1) && !is_obstacle(y2, x2)){
make_move(y,x,d1,d2);
} else if (!is_obstacle(m->tiles[y1][x1]) && !is_obstacle(m->tiles[y2][x2])){
make_move(mon,m,y,x,d1,d2);
return 1;
} else if (!is_obstacle(y1,x1)){
make_move(y,x,d1,UNKNOWN);
} else if (!is_obstacle(m->tiles[y1][x1])){
make_move(mon,m,y,x,d1,DIR_UNKNOWN);
return 1;
}
return 0;
}
// move the monster to the right or the left depending on the player's position
int move_up_or_down(int y_monster, int x_monster, int y_player){
if (y_monster > y_player )
return ok_move(y_monster,x_monster, UP, UP);
int move_up_or_down(monsters* mon, map* m, int y_monster, int x_monster, int y_player){
if (y_monster > y_player)
return ok_move(mon, m, y_monster,x_monster, DIR_UP, DIR_UP);
else if (y_monster < y_player)
return ok_move(y_monster,x_monster, DOWN, DOWN);
return ok_move(mon, m, y_monster,x_monster, DIR_DOWN, DIR_DOWN);
return 0;
}
// move the monster to the right or the left depending on the player's position
int move_left_or_right(int y_monster, int x_monster, int x_player){
if (x_monster > x_player )
return ok_move(y_monster,x_monster, LEFT, LEFT);
int move_left_or_right(monsters* mon, map* m, int y_monster, int x_monster, int x_player){
if (x_monster > x_player)
return ok_move(mon, m, y_monster,x_monster, DIR_LEFT, DIR_LEFT);
else if (x_monster < x_player)
return ok_move(y_monster,x_monster, RIGHT, RIGHT);
return ok_move(mon, m, y_monster,x_monster, DIR_RIGHT, DIR_RIGHT);
return 0;
}
// move the monster to one of the four corners
int move_to_corner(int y_monster, int x_monster, int y_player, int x_player){
int move_to_corner(monsters* mon, map* m, int y_monster, int x_monster, int y_player, int x_player){
if (x_monster > x_player && y_monster > y_player)
return ok_move(y_monster,x_monster, UP, LEFT) || ok_move(y_monster,x_monster, LEFT, UP);
return ok_move(mon, m, y_monster,x_monster, DIR_UP, DIR_LEFT) || ok_move(mon, m, y_monster,x_monster, DIR_LEFT, DIR_UP);
else if (x_monster > x_player && x_monster < y_player)
return ok_move(y_monster,y_player, DOWN, LEFT) || ok_move(y_monster,x_monster, LEFT, DOWN);
return ok_move(mon, m, y_monster,y_player, DIR_DOWN, DIR_LEFT) || ok_move(mon, m, y_monster,x_monster, DIR_LEFT, DIR_DOWN);
else if (x_monster < x_player && y_monster > y_player)
return ok_move(y_monster,x_monster, RIGHT, UP) || ok_move(y_monster,x_monster, UP, RIGHT);
return ok_move(mon, m, y_monster,x_monster, DIR_RIGHT, DIR_UP) || ok_move(mon, m, y_monster,x_monster, DIR_UP, DIR_RIGHT);
else if (x_monster < x_player && y_monster < y_player)
return ok_move(y_monster,x_monster, RIGHT, DOWN) || ok_move(y_monster,x_monster, DOWN, RIGHT);
return ok_move(mon, m, y_monster,x_monster, DIR_RIGHT, DIR_DOWN) || ok_move(mon, m, y_monster,x_monster, DIR_DOWN, DIR_RIGHT);
return 0;
}
int follow_player(int * y, int * x){
int follow_player(monsters* mon, map* m, int * y, int * x){
int y_monster = *y;
int x_monster = *x;
map * m = current_map();
int y_player = m->player_y, x_player = m->player_x;
if (x_player == x_monster){ // same column
return move_up_or_down(y_monster, x_monster, y_player);
return move_up_or_down(mon, m, y_monster, x_monster, y_player);
} else if (y_monster==y_player){ // same line
return move_left_or_right(y_monster, x_monster, x_player);
return move_left_or_right(mon, m, y_monster, x_monster, x_player);
} else if ((x_player==x_monster+1 || x_player==x_monster-1) && (y_player==y_monster+1 || y_player==y_monster-1)){ // corners
return move_to_corner(y_monster, x_monster, y_player, x_player);
return move_to_corner(mon, m, y_monster, x_monster, y_player, x_player);
} else if (x_player==x_monster+1 || x_player==x_monster-1){ // one tile to the left or the right
#ifdef line_first
return move_up_or_down(y_monster, x_monster, x_player) || move_to_corner(y_monster, x_monster, y_player, x_player);
return move_up_or_down(mon, m, y_monster, x_monster, x_player) || move_to_corner(mon, m, y_monster, x_monster, y_player, x_player);
#else
return move_to_corner(y_monster, x_monster, y_player, x_player) || move_up_or_down(y_monster, x_monster, y_player);
return move_to_corner(mon, m, y_monster, x_monster, y_player, x_player) || move_up_or_down(mon, m, y_monster, x_monster, y_player);
#endif
} else if (y_player==y_monster+1 || y_player==y_monster-1){ // one tile upper or lower
#ifdef line_first
return move_left_or_right(y_monster, x_monster, x_player) || move_to_corner(y_monster, x_monster, y_player, x_player);
return move_left_or_right(mon, m, y_monster, x_monster, x_player) || move_to_corner(mon, m, y_monster, x_monster, y_player, x_player);
#else
return move_to_corner(y_monster, x_monster, y_player, x_player) || move_left_or_right(y_monster, x_monster, x_player);
return move_to_corner(mon, m, y_monster, x_monster, y_player, x_player) || move_left_or_right(mon, m, y_monster, x_monster, x_player);
#endif
} else {
#ifdef line_first
return move_left_or_right(y_monster, x_monster, x_player) || move_up_or_down(y_monster, x_monster, y_player) || move_to_corner(y_monster, x_monster, y_player, x_player);
return move_left_or_right(mon, m, y_monster, x_monster, x_player) || move_up_or_down(mon, m, y_monster, x_monster, y_player) || move_to_corner(mon, m, y_monster, x_monster, y_player, x_player);
#else
#endif
return move_to_corner(y_monster, x_monster, y_player, x_player) || move_up_or_down(y_monster, x_monster, y_player) || move_left_or_right(y_monster, x_monster, x_player);
return move_to_corner(mon, m, y_monster, x_monster, y_player, x_player) || move_up_or_down(mon, m, y_monster, x_monster, y_player) || move_left_or_right(mon, m, y_monster, x_monster, x_player);
}
}
void circle(int y, int x){
if(y==6 && x!=6 )
move_entity(y,x,y,x-1); // left
else if (y == 4 && x!=10)
move_entity(y,x,y,x+1); //right
else if(x == 6 && y!=4)
move_entity(y,x,y-1,x); //up
else if(x == 10 && y!=6)
move_entity(y,x,y+1,x); //down
void circle(monsters* mon, map* m, int y, int x) {
if (y == 6 && x != 6 && m->tiles[y][x-1] != 'M')
update_monster(mon,m,y,x,y,x-1); // left
else if (y == 4 && x!=10 && m->tiles[y][x+1] != 'M')
update_monster(mon,m,y,x,y,x+1); //right
else if(x == 6 && y!=4 && m->tiles[y-1][x] != 'M')
update_monster(mon,m,y,x,y-1,x); //up
else if(x == 10 && y!=6 && m->tiles[y+1][x] != 'M')
update_monster(mon,m,y,x,y+1,x); //down
}
void come_and_go(map * m, int y, int x){
int i = coord_idx(y,x);
int dir = m->entities[i]->stats[1];
if(x==m->width-2){
m->entities[i]->stats[1] = 1;
move_entity(y,x,y,x-1);
int search_monster(monsters* mon, map* m, int y, int x) {
for (int i = 0; i < mon->length; i++)
{
if (mon->info[i].x == x && mon->info[i].y == y)
return i;
}
else if (x == 2){
m->entities[i]->stats[1] = 0;
move_entity(y,x,y,x+1);
return -1;
}
void come_and_go(monsters* mon, map * m, int y, int x){
int monster_id = search_monster(mon, m, y, x);
if (monster_id == -1)
return;
int dir = mon->info[monster_id].dir;
if(x==m->width-2 || m->tiles[y][x+1] == '@' || m->tiles[y][x+1] == 'M') {
mon->info[monster_id].dir = DIR_LEFT;
update_monster(mon,m,y,x,y,x-1);
}
else if (x == 2 || m->tiles[y][x-1] == 'M') {
mon->info[monster_id].dir = DIR_RIGHT;
update_monster(mon,m,y,x,y,x+1);
}
else if (dir == DIR_RIGHT)
update_monster(mon,m,y,x,y,x+1);
else if (dir == DIR_LEFT)
update_monster(mon,m,y,x,y,x-1);
else if (dir == DIR_DOWN) {
mon->info[monster_id].dir = DIR_LEFT;
update_monster(mon,m,y,x,y,x-1);
}
}
// verify if the player is seen by the monster
void is_player_seen(monsters* mon, map * m, int y, int x){
int monster_id = search_monster(mon, m, y, x);
if (monster_id == -1)
return;
int dir = mon->info[monster_id].dir;
#ifndef BUG
if (dir == DIR_RIGHT && m->player_x > x && m->player_y == y)
#else
if (dir == DIR_RIGHT && m->player_y == y)
#endif
mon->info[monster_id].player_seen = true;
#ifndef BUG
else if (dir == DIR_LEFT && m->player_x < x && m->player_y == y)
#else
else if (dir == DIR_LEFT && m->player_y == y)
#endif
mon->info[monster_id].player_seen = true;
#ifndef BUG
else if (dir == DIR_UP && m->player_y < y && m->player_x == x)
#else
else if (dir == DIR_UP && m->player_x == x)
#endif
mon->info[monster_id].player_seen = true;
}
// move the monster to the player's position
void catch_player(monsters* mon, map * m, int y, int x){
int monster_id = search_monster(mon, m, y, x);
if (y < m->player_y && !is_obstacle(m->tiles[y+1][x]) && m->tiles[y+1][x] != 'M' && m->tiles[y+1][x] != '@') {
mon->info[monster_id].dir = DIR_DOWN;
update_monster(mon,m,y,x,y+1,x);
} else if (y > m->player_y && !is_obstacle(m->tiles[y-1][x]) && m->tiles[y-1][x] != 'M' && m->tiles[y-1][x] != '@') {
mon->info[monster_id].dir = DIR_UP;
update_monster(mon,m,y,x,y-1,x);
} else if (x < m->player_x && !is_obstacle(m->tiles[y][x+1]) && m->tiles[y][x+1] != 'M' && m->tiles[y][x+1] != '@') {
mon->info[monster_id].dir = DIR_RIGHT;
update_monster(mon,m,y,x,y,x+1);
} else if (x > m->player_x && !is_obstacle(m->tiles[y][x-1]) && m->tiles[y][x-1] != 'M' && m->tiles[y][x-1] != '@') {
mon->info[monster_id].dir = DIR_LEFT;
update_monster(mon,m,y,x,y,x-1);
}
else if (dir == 0)
move_entity(y,x,y,x+1);
else if (dir == 1)
move_entity(y,x,y,x-1);
}
// move the monster once and verify to not move twice a monster.
void move_monster(map * m){
void move_monsters(monsters* mon, map * m){
int done[8], len = 0;
for (int y = 0; y < m->height; y++){
for (int x = 0; x < m->width; x++){
int i = coord_idx(y,x);
if (m->entities[i] && m->entities[i]->category == MONSTER){
int value = m->entities[i]->stats[0];
if (!in_list(value, done, len)){
if (!strcmp(m->name, "a first room"))
come_and_go(m,y,x);
else if (!strcmp(m->name, "a second room"))
circle(y,x);
else if (!strcmp(m->name, "a third room"))
follow_player(&y,&x);
done[len] = value;
if (m->tiles[y][x] == 'M'){
int id = search_monster(mon, m, y, x);
if (id != -1 && !in_list(id, done, len)){
if (strcmp(m->name, "third_room") != 0)
is_player_seen(mon,m,y,x);
if (mon->info[id].player_seen && strcmp(m->name, "third_room") != 0)
catch_player(mon,m,y,x);
else if (!strcmp(m->name, "first_room"))
come_and_go(mon,m,y,x);
else if (!strcmp(m->name, "second_room"))
circle(mon,m,y,x);
else if (!strcmp(m->name, "third_room"))
follow_player(mon,m,&y,&x);
done[len] = id;
len++;
}
}
}
}
}
void parse_input(command * c){
map * m = current_map();
for (int i = 0; c->command_buffer[i]!='\n' || c->command_buffer[i]!='\0'; i++){
if (c->command_buffer[i]=='R')
right(m->player_y, m->player_x);
else if (c->command_buffer[i]=='L')
left(m->player_y, m->player_x);
else if (c->command_buffer[i]=='D')
down(m->player_y, m->player_x);
else if (c->command_buffer[i]=='U')
up(m->player_y, m->player_x);
else if (c->command_buffer[i]=='\0' || c->command_buffer[i]=='\n' )
return;
else if (c->command_buffer[i]!='W')
printf("Unknown input command.\n");
move_monster(m);
show_map();
apply_events();
if (win||defeat){
return;
}
}
}
\ No newline at end of file
#ifndef INPUT_MANAGER_H
#define INPUT_MANAGER_H
#include "../../engines/fullgame/agdbentures.h"
#include "engine/agdbentures.h"
#include "custom_map.h"
#include <unistd.h>
// examine la commande c et appelle les fonctions d'action ou de déplacement correspondantes
//return 1 if the value given in parameter is in the list.
int in_list(int value, int *list, int len);
// apply the movement from (y,x) and to direction d1 first then d2 if possible.
void make_move(monsters* mon, map *m, int y, int x, direction d1, direction d2);
// verify if a move is possible and apply it if so
int ok_move(monsters* mon, map *m, int y, int x, direction d1, direction d2);
// move the monster to the right or the left depending on the player's position
int move_up_or_down(monsters* mon, map *m, int y_monster, int x_monster, int y_player);
// move the monster to the right or the left depending on the player's position
int move_left_or_right(monsters* mon, map *m, int y_monster, int x_monster, int x_player);
// move the monster to one of the four corners
int move_to_corner(monsters* mon, map *m, int y_monster, int x_monster, int y_player, int x_player);
// follow movement (3rd monster pattern)
int follow_player(monsters* mon, map *m, int *y, int *x);
void parse_input(command * c);
// circle movement (2nd monster pattern)
void circle(monsters* mon, map *m, int y, int x);
// returns the id of the monster located at coordinates (x,y) or -1
int search_monster(monsters *mon, map *m, int y, int x);
// come and go movement (1st monster pattern)
void come_and_go(monsters *mon, map *m, int y, int x);
// search for the monster at coordinates (x,y) and return its id or -1
int search_monster(monsters* mon, map* m, int y, int x);
// move every monster once and verify not to move twice a monster.
void move_monsters(monsters *mon, map *m);
// examine la commande c et appelle les fonctions d'action ou de déplacement correspondantes
// void parse_input(game_instance* game, monsters* mon, command * c);
#endif // INPUT_MANAGER_H
\ No newline at end of file
#endif
\ No newline at end of file
......@@ -2,113 +2,146 @@
* level_title: Avoid Monster
* program_name: avoid_monster
* exec_name: avoid_monster
* engine_name: fullgame
* engine_name: map_stack
*
* available_commands: edit next step continue interrupt
*
* player_mode: map_stack
*
* interactive: True
*
* characters: skeleton:4
*
* OBJskeleton_1: char_rep M
* OBJskeleton_2: char_rep M
* OBJskeleton_3: char_rep M
* OBJskeleton_4: char_rep M
*
* verify_exit: cond exit_x == 4
* verify_exit: cond exit_y == 7
* verify_always: must_call init_monsters
* verify_always: must_call move_monsters
* verify_always: must_call verify_monster
* verify_always: must_call is_player_seen
*
* WOP: messageFR intro
* Enfuis toi de cette prison, j'ai récupéré cette clé sur un monstre,
* prends là et échappe toi !
* Fais attention aux monstres, ils sont très dangereux !
* S'ils te vois, ils te poursuivront jusqu'à ce qu'ils t'attrapent !
* EndOfMessage
*
* WOP: messageEN intro
* Escape from this prison, I got this key off a monster, take it and escape!
* Watch out for monsters, they're very dangerous!
* If they see you, they'll chase you until they catch you!
* EndOfMessage
*
* arcade_maps: main first_room.tmx
* arcade_maps: second_room second_room.tmx
* arcade_maps: third_room third_room.tmx
*/
#include "../../engines/fullgame/agdbentures.h"
#include "events_map.h"
#include "input_manager.h"
#include "engine/agdbentures.h"
#include "custom_map.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int exit_x = 15;
int exit_y = 1;
extern int win, defeat;
int execute_loop(bool manual_mode){
if (defeat){
return 0;
void init_maps(game_instance* game) {
char* head_names[3] = {"third", "second", "first"};
char *tail_name = "_room";
char name[15];
for (int i = 0; i < 3; i++) {
strcpy(name, head_names[i]);
strcat(name, tail_name);
map *m = load_map(name, i == 0 ? str_map3 : i == 1 ? str_map2 : str_map1);
push_on_stack(game->map_stack, m);
}
win = 0, defeat = 0;
command * com = get_next_command();
exit_main_loop = false;
// The Holy Main Loop
while (!exit_main_loop) {
parse_input(com);
/* since the events may be applied if the input is FORWARD_N,
we need to check to avoid triggering the same event twice */
if (!exit_main_loop)
apply_events();
if (!exit_main_loop)
com = get_and_free_input(com);
}
// plus aucun input mais on a pas encore gagné ou perdu -> défaite
if (!manual_mode && com == NULL && !exit_main_loop){
level_failed();
return 1;
void execute_loop(game_instance* game, monsters* mon) {
int dest_y, dest_x;
map* room_map = current_map(game->map_stack);
// inputs loop
while (!game->exit_main_loop) {
// read command
command * input_command = get_next_command();
char* command = input_command->command_buffer;
direction dir = direction_from_string(command);
// if the direction is meaningful try to move
if (dir != DIR_UNKNOWN) {
// Lookup for the predicted destination
room_map->player_direction = dir;
player_look_forward(room_map, &dest_y, &dest_x);
// If the destination is empty, go there
if (room_map->tiles[dest_y][dest_x] == ' ') {
move_player(room_map, dest_y, dest_x, dir);
// if there's a monster, player loses
} else if (room_map->tiles[dest_y][dest_x] == '-' || room_map->tiles[dest_y][dest_x] == '|' || room_map->tiles[dest_y][dest_x] == '+') {
continue;
} else if (room_map->tiles[dest_y][dest_x] == 'M') {
move_player(room_map, dest_y, dest_x, dir);
message("The monster catches you!\n");
level_failed(game,1);
exit(EXIT_FAILURE);
// if player reaches the exit, exit the loop
} else if (room_map->tiles[dest_y][dest_x] == '@') {
printf("You reached the exit!\n");
move_player(room_map, dest_y, dest_x, dir);
game->exit_main_loop = true;
break;
}
} else if (!strcmp(command,"W") || !strcmp(command,"w") || !strcmp(command,"WAIT") || !strcmp(command,"wait")) {
message("You stand still and wait"); // wait one turn
} else {
printf("Unknown command %s\n", command);
continue;
}
printf("player x=%d y=%d\n", room_map->player_x, room_map->player_y);
move_monsters(mon, room_map);
verify_monster(game, mon);
show_map(room_map);
}
return 0;
}
void change_map(game_instance* game, monsters* mon, int i) {
pop_from_stack(game->map_stack);
game->exit_main_loop = false;
int main(int argc, char ** argv) {
bool manual_mode = true;
if (argc > 1)
manual_mode = false;
if (manual_mode) {
printf("Manual mode. \nUse Ctrl+C to quit.\n");
} else {
if (!init_inputs_file(argv[1])) {
printf("Error while reading the inputs!\n");
return EXIT_FAILURE;
}
}
init_map_stack();
add_event((void *)verify_monster, NULL);
add_event((void *)verify_exit, NULL);
// first room
printf("You have to avoid the monster using the command R U L D and W(ait).\n");
init_map(load_map("a first room", str_map1));
if (manual_mode) {
printf("First room\n");
show_map();
}
if (execute_loop(manual_mode)){
remove_all_events();
free_map_stack();
close_inputs_file();
return 0;
if (i == 0) {
exit_x = 8;
exit_y = 5;
} else if (i == 1) {
exit_x = 4;
exit_y = 7;
}
}
//2nd room
int main() {
game_instance* game = init_game();
monsters* monsters_data = malloc(sizeof(monsters));
map *room;
init_maps(game);
message("You have to avoid the monsters using the directional arrows and W(ait).");
init_map(load_map("a second room", str_map2));
if (manual_mode && !defeat) {
printf("\n\nSecond room\n");
show_map();
}
if (execute_loop(manual_mode)){
remove_all_events();
free_map_stack();
close_inputs_file();
return 0;
}
//3rd room
init_map(load_map("a third room", str_map3));
if (manual_mode && !defeat) {
printf("\n\nThird room\n");
show_map();
}
if (execute_loop(manual_mode)){
remove_all_events();
free_map_stack();
close_inputs_file();
return 0;
// rooms loop
for (int i = 0; i < 3; i++) {
room = current_map(game->map_stack);
init_monsters(room, monsters_data);
printf("Room n°%d\n", i+1);
execute_loop(game, monsters_data);
change_map(game, monsters_data, i);
}
free(monsters_data);
free_map_stack(game->map_stack);
remove_all_events();
free_map_stack();
close_inputs_file();
return EXIT_SUCCESS;
verify_exit(room);
}
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.8" tiledversion="1.8.0" orientation="orthogonal" renderorder="right-down" width="20" height="10" tilewidth="32" tileheight="32" infinite="0" backgroundcolor="#000000" nextlayerid="5" nextobjectid="11">
<tileset firstgid="1" source="../../../resources/tiles/[Base]BaseChip_pipo.json"/>
<tileset firstgid="1065" source="../../../resources/tiles/[A]Grass_pipo.json"/>
<tileset firstgid="1593" source="../../../resources/tiles/[A]Water_pipo.json"/>
<layer id="1" name="floor" width="20" height="10">
<data encoding="csv">
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
</data>
</layer>
<layer id="2" name="decorations" width="20" height="10">
<data encoding="csv">
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
</data>
</layer>
<layer id="3" name="walls" width="20" height="10">
<data encoding="csv">
449,458,458,458,458,458,458,458,458,458,458,458,458,458,458,458,451,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
452,0,0,0,0,0,0,0,336,0,0,0,0,0,0,0,452,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
449,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,451,556,0,0,
457,458,458,458,458,458,458,458,458,458,458,458,458,458,458,458,459,556,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,0,0
</data>
</layer>
<layer id="3" name="decorations_top" width="20" height="10">
<data encoding="csv">
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,455,455,455,455,455,455,455,455,455,455,455,455,455,455,455,0,0,2814,2815,
909,908,0,0,0,0,0,925,925,925,0,0,0,0,0,908,909,0,2814,2815,
917,916,0,0,0,0,0,933,933,933,0,0,0,0,0,916,917,0,2814,2815
</data>
</layer>
<objectgroup id="4" name="objects"/>
</map>
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.8" tiledversion="1.8.0" orientation="orthogonal" renderorder="right-down" width="20" height="14" tilewidth="32" tileheight="32" infinite="0" backgroundcolor="#000000" nextlayerid="5" nextobjectid="11">
<tileset firstgid="1" source="../../../resources/tiles/[Base]BaseChip_pipo.json"/>
<tileset firstgid="1065" source="../../../resources/tiles/[A]Grass_pipo.json"/>
<tileset firstgid="1593" source="../../../resources/tiles/[A]Water_pipo.json"/>
<layer id="1" name="floor" width="20" height="14">
<data encoding="csv">
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
</data>
</layer>
<layer id="2" name="decorations" width="20" height="14">
<data encoding="csv">
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,488,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,496,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1453,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,1461,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,1465,1451,1451,1451,1451,1451,1451,1451,1451,1451,1451,1458,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1461,0,0,2814,2815
</data>
</layer>
<layer id="3" name="walls" width="20" height="14">
<data encoding="csv">
449,458,458,458,458,458,458,458,458,458,458,458,458,458,458,458,451,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
452,0,210,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
452,0,218,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,210,0,210,0,452,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,219,217,220,0,452,556,0,0,
452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452,556,0,0,
449,450,450,450,0,450,450,450,450,450,450,450,450,450,450,450,451,556,0,0,
457,458,458,458,0,458,458,458,458,458,458,458,458,458,458,458,459,556,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,0,0
</data>
</layer>
<layer id="3" name="decorations_top" width="20" height="14">
<data encoding="csv">
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2814,2815,
0,455,455,828,487,828,455,455,455,455,455,455,455,455,455,455,0,0,2814,2815,
909,908,0,836,0,836,0,925,925,925,0,0,0,0,0,908,909,0,2814,2815,
917,916,0,0,0,0,0,933,933,933,0,0,0,0,0,916,917,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
</data>
</layer>
<objectgroup id="4" name="objects"/>
</map>
......@@ -24,7 +24,6 @@ from arcade.experimental.crt_filter import CRTFilter
from config import Config
from language import message
from utils import log, show_threads
from level.objects import Object
from graphic.style import (
MenuButton,
......@@ -49,7 +48,7 @@ from graphic.amap import Amap
from graphic.sprites.path import find_path, to_absolute, to_relative
from level.console import ConsoleInputThread
from level.action import Action
from progress.progress_manager import progress
from progress.progress_manager import ProgressionManager
# pylint: disable=fixme unused-argument too-many-instance-attributes too-many-branches
......@@ -69,8 +68,9 @@ class GameView(EmptyView):
self.layers: dict[str, arcade.SpriteList]
self.player: SpPlayer
self.wop: NPC
self.enemy: NPC
self.objects = None # dictionnary for sprite objects
self.characters = {} # character objects
self.has_started = False # whether the inferior has started or not (
self.executing = (
False # whether the inferior is executing (running or on pause) or not
......@@ -364,24 +364,15 @@ class GameView(EmptyView):
log.debug(f"New command for level: {cmd}")
self.cmd_buttons[cmd].child.start_blinking()
def compile_reload_level(self, event, target='all', force=False):
success = self.compile_level(target, force)
if success:
self.level.reload_program()
self.trigger_restart_level()
self.code_window.reload()
return success
def compile_level(self, target='all', force=False):
print("\n"+message('compiling/loading'))
result = self.level.compile_source(capture_output=True, target=target, force=force)
self.level.reload_program()
self.code_window.reload()
if result.returncode == 0:
print(message('compilation/success'))
self.trigger_restart_level()
return True
# otherwise, show compilation errors
......@@ -455,14 +446,9 @@ class GameView(EmptyView):
tm = arcade.load_tilemap(
map_path,
layer_options={"objects": {"custom_class": spo.SpObject},
"characters": {"custom_class": spo.SpObject}
},
layer_options={"objects": {"custom_class": spo.SpObject}},
offset=tilemap_off,
) # type: ignore
if map_name != 'main' and not self.metadata['map_width'] and not self.metadata['map_width']:
self.level.maps[map_name].set_size(tm.width, tm.height)
self.amap.reset(tm.width, tm.height, map_off_x, map_off_y)
......@@ -471,6 +457,12 @@ class GameView(EmptyView):
log.debug(f"Offset of map: {map_off_x}x{map_off_y}")
objects = {}
# TODO EXIT REMOVE THIS LATER
if map_name == "tele":
# remove exit from main map
print("DO STUFF WITH EXIT AND TELE LEVEL")
# del self.tmx_maps["main"]["objects"]["exit"]
objects["exit"] = self.exit
if 'objects' not in tm.sprite_lists:
# create empty list
......@@ -504,48 +496,28 @@ class GameView(EmptyView):
obj.visible = False
objects[obj.name] = obj
object = Object(init_x=x, init_y=y, **(obj.properties | self.metadata['objects'][obj.name]))
object.set_out_queue(self.level.out_queue)
self.level.maps[map_name].add_object(object)
# Add objects found in the level metadata, if not present in the .tmx
for name in self.metadata['objects']:
if name in objects:
log.debug(f"{name} already present in objects")
continue
log.debug(f"Adding {name} not already present in objects to the tile map")
# TODO(flo): why is there these hard-coded lines?
if name == "guard":
obj = self.guard
elif name == "enemy":
obj = self.enemy
elif name == "cook":
obj = self.cook
else:
log.error(f"Do not know how to include object {name}")
sys.exit(1)
objects[name] = obj
tm.sprite_lists["objects"].append(obj)
#Recovering characters from layer 'characters' in the .tmx
if 'characters' not in tm.sprite_lists:
# create empty list
tm.sprite_lists['characters'] = arcade.SpriteList()
for char in tm.sprite_lists["characters"]:
for p, v in char.properties.items():
setattr(char, p, v)
if char.name == 'GenericObject':
log.warning("Every character should have a name")
log.debug(f"Found character {char.name} on map {map_name}")
#getting the file name of the sprite
texture = char.texture
start, end = texture.name.rsplit('.',maxsplit=1)
sprite_file = start+f".{end.split('-')[0]}"
#Creating the character's sprite
char_sprite = spo.SpNPC(sprite_file, self.amap)
#recovering the direction
directions = [cst.Direction.DOWN, cst.Direction.LEFT, cst.Direction.RIGHT, cst.Direction.UP]
sprite_y = int(end.split('-')[2])
texture_line = sprite_y // char.texture.height
char_direction = directions[texture_line]
#Storing the character and it's data
self.characters[char.name] = char_sprite
tm.sprite_lists['objects'].append(char_sprite)
objects[char.name] = char_sprite
x, y = to_relative((char.center_x, char.center_y), self.amap)
obj = Object(**(self.metadata['objects'][char.name] | char.properties), init_x = x, init_y = y)
obj.direction = char_direction
obj.set_out_queue(self.level.out_queue)
self.level.maps[map_name].add_object(obj)
# Get .tmx coordinates, referenced as "objects" by the tiled editor.
coords = {}
......@@ -567,7 +539,6 @@ class GameView(EmptyView):
coord.coord_x = x
coord.coord_y = y
coords[name] = coord
self.level.maps[map_name].add_coordinates(coord)
self.tmx_maps[map_name] = {
"tile_map": tm,
......@@ -710,13 +681,33 @@ class GameView(EmptyView):
self.adjust_buttons()
self.scale = None # TODO: think what is necessary for scale
# TODO: really need to recreate WOP? Should be the same for all levels
# self.wop = spo.SpWop(self.metadata["arcade_skins"]["wop_main"], self.amap)
# log.debug(f"created wop {self.wop}")
# self.guard = spo.SpNPC(self.metadata["arcade_skins"]["guard"], self.amap)
# log.debug(f"created guard {self.guard}")
# self.knight = spo.SpNPC(self.metadata["arcade_skins"]["knight"], self.amap)
# log.debug(f"created knight {self.knight}")
self.wop = spo.SpWop(self.metadata["arcade_skins"]["wop_main"], self.amap)
log.debug(f"created wop {self.wop}")
self.guard = spo.SpNPC(self.metadata["arcade_skins"]["guard"], self.amap)
self.guard.name = "guard"
log.debug(f"created guard {self.guard}")
self.cook = spo.SpNPC(self.metadata["arcade_skins"]["cook"], self.amap)
log.debug(f"created cook {self.cook}")
self.enemy = spo.SpEnemy(self.metadata["arcade_skins"]["enemy"], self.amap)
log.debug(f"created enemy {self.enemy}")
# Initializing maps
self.load_maps()
if 'map_width' in self.metadata:
log.debug(
f"Map width from metadata {self.metadata['map_width']} vs arcade {self.amap.width}"
)
assert self.metadata['map_width'] <= self.amap.width
else:
self.metadata['map_width'] = self.amap.width
if 'map_height' in self.metadata:
log.debug(
f"Map height from metadata {self.metadata['map_height']} vs arcade {self.amap.height}"
)
assert self.metadata['map_height'] <= self.amap.height
else:
self.metadata['map_height'] = self.amap.height
# combine objects/coordinates of all maps to pass to the tracker
sp_objs = {'exit': self.exit}
......@@ -729,10 +720,6 @@ class GameView(EmptyView):
# Open or re-open code window if necessary
code_window.check_or_reopen()
## Instantiate the level object, must be done before initializing maps
# as objects will have the reference to the level_output_queue to send
# payloads to the GUI
# Clear the input queue
while not self.level_input_queue.empty():
item = self.level_input_queue.get()
......@@ -751,39 +738,14 @@ class GameView(EmptyView):
)
self.console_input_thread.set_level(self.level)
# Initializing WOP
self.wop = spo.SpWop(self.metadata["arcade_skins"]["wop_main"], self.amap)
log.debug(f"created wop {self.wop}")
# Initializing maps
self.load_maps()
if 'map_width' in self.metadata:
log.debug(
f"Map width from metadata {self.metadata['map_width']} vs arcade {self.amap.width}"
)
assert not self.metadata['map_width'] or self.metadata['map_width'] <= self.amap.width
else:
self.metadata['map_width'] = self.amap.width
if 'map_height' in self.metadata:
log.debug(
f"Map height from metadata {self.metadata['map_height']} vs arcade {self.amap.height}"
)
assert not self.metadata['map_height'] or self.metadata['map_height'] <= self.amap.height
else:
self.metadata['map_height'] = self.amap.height
# Verify if level needs to be re-compiled
# (e.g., if source more recent than executable)
ret = self.compile_level()
ret = self.compile_reload_level(None)
if not ret:
log.error("Cannot launch level")
return
self.level.load_program()
self.code_window.reload()
self.set_reset_level() # prepare the level with common code used also for restart
# start the thread that will handle easytracker for this level
......@@ -810,14 +772,16 @@ class GameView(EmptyView):
self.teleport_in.reset()
self.teleport_out.reset()
self.enemy.set_reset()
# Put the player in the correct visibility state
self.player.set_reset()
self.player.visible = self.level.player.visible
self.player.visible = self.level.map.player.visible
self.player.set_relative_position(
self.level.player.coord_x, self.level.player.coord_y
self.level.map.player.coord_x, self.level.map.player.coord_y
)
self.exit.set_relative_position(
self.level.maps["main"].exit.coord_x, self.level.maps["main"].exit.coord_y
self.level.map.exit.coord_x, self.level.map.exit.coord_y
)
# initial placement: show exit if not on map
self.center_camera_to_player()
......@@ -828,9 +792,8 @@ class GameView(EmptyView):
# Hide NPCs
# self.guard.visible = False
for char in self.characters.values():
char.set_reset()
self.guard.set_reset()
self.cook.set_reset()
# clear output log
self.output_logbox.reset()
......@@ -1118,16 +1081,11 @@ class GameView(EmptyView):
self.player.rescale(self.scale)
self.wop.rescale(self.scale)
self.guard.rescale(self.scale)
self.enemy.rescale(self.scale)
self.exit.rescale(self.scale)
self.breaklight.rescale(self.scale)
for char in self.characters.values():
char.rescale(self.scale)
for obj in self.objects.values():
obj.rescale(self.scale)
log.debug(f"Rescaling {obj.name}")
self.cook.rescale(self.scale)
self.teleport_in.rescale(self.scale)
self.teleport_out.rescale(self.scale)
......@@ -1239,10 +1197,8 @@ class GameView(EmptyView):
f"Try going manually in {self.level.source_level_dir}\n"
"and fix the problem or do a `git reset --hard init' there"
)
# TODO: do something like self.level.send_level_control('exit')
# maybe ?
self.level = None
self.load_view("end_game")
self.level = None
return
# raise RuntimeError("Level thread died unexpectedly")
......@@ -1262,6 +1218,7 @@ class GameView(EmptyView):
# Update all regular sprites that are always present
self.player.update()
self.wop.update()
self.enemy.update()
self.exit.update()
self.breaklight.update()
self.teleport_in.update()
......@@ -1513,13 +1470,6 @@ class GameView(EmptyView):
self.adjust_buttons()
return
if action == "show_game":
if self.window._current_view == self:
return
else:
self.load_view("game")
return
raise NotImplementedError
def gdb_command_update(self, cmd):
......@@ -1546,6 +1496,8 @@ class GameView(EmptyView):
obj = self.player
elif who == "wop":
obj = self.wop
elif who == "enemy":
obj = self.enemy
else:
objname = payload["object_name"]
......@@ -1588,16 +1540,11 @@ class GameView(EmptyView):
if act != "move":
return
# Only one change allowed per payload, otherwise there are problems
# since the payloads would be aliases
for ch in ['speed', 'far_move']:
chkey = 'change/' + ch
if chkey in payload:
payload['action'] = Action(chkey)
payload['value'] = payload[chkey]
obj.append_action(payload)
return
if 'change/speed' in payload:
payload['action'] = Action('change/speed')
payload['value'] = payload['change/speed']
obj.append_action(payload)
return
if payload.get('talks', False):
log.error("Must not use the 'talks' field anymore")
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment