- Carrega de l'habitació des de arxiu
- Traslladem a jutil funcionetes varies - Comencem a implementar carrega de actors des de arxiu - Comencem a implementar els templates de actors
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
width: 2
|
width: 2
|
||||||
height: 2
|
height: 3
|
||||||
door-xp: 0 1
|
door-height-xn: 0
|
||||||
color: 9
|
color: cyan
|
||||||
floor-texture: 0
|
floor-texture: 1
|
||||||
wall-texture: 0
|
wall-texture: 1
|
||||||
door-texture: 0
|
door-texture: 1
|
||||||
under-door-texture: 0
|
under-door-texture: 1
|
||||||
|
|
||||||
actor{
|
actor{
|
||||||
template: box
|
template: box
|
||||||
|
|||||||
15
data/templates.txt
Normal file
15
data/templates.txt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
actor{
|
||||||
|
name: BOX
|
||||||
|
bmp: test.gif
|
||||||
|
bmp-rect: 32 0 32 32
|
||||||
|
bmp-offset: 0 32
|
||||||
|
pos: 32 32 8
|
||||||
|
size: 8 8 8
|
||||||
|
orient: NONE
|
||||||
|
movement: CW
|
||||||
|
anim-cycle: WALK
|
||||||
|
anim-speed: 0
|
||||||
|
flags: PUSH GRAV
|
||||||
|
react-mask: NONE
|
||||||
|
react-push: NONE
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "actor.h"
|
#include "actor.h"
|
||||||
#include "jdraw.h"
|
#include "jdraw.h"
|
||||||
#include "jinput.h"
|
#include "jinput.h"
|
||||||
|
#include "jfile.h"
|
||||||
|
#include "jutil.h"
|
||||||
#include "room.h"
|
#include "room.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -45,6 +47,28 @@ namespace actor
|
|||||||
return act;
|
return act;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void createFromFile(char **buffer)
|
||||||
|
{
|
||||||
|
actor_t *act = (actor_t*)malloc(sizeof(actor_t));
|
||||||
|
if (*buffer)
|
||||||
|
{
|
||||||
|
while (**buffer != 0)
|
||||||
|
{
|
||||||
|
const char* key = file::readString(buffer);
|
||||||
|
|
||||||
|
if (util::strcomp(key, "pos:")) {
|
||||||
|
act->pos.x = file::readInt(buffer);
|
||||||
|
act->pos.y = file::readInt(buffer);
|
||||||
|
act->pos.z = file::readInt(buffer);
|
||||||
|
} else if (util::strcomp(key, "height:")) {
|
||||||
|
const int val = file::readInt(buffer);
|
||||||
|
inner_h = SDL_clamp(val, 0, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setDirty(act, true);
|
||||||
|
}
|
||||||
|
|
||||||
const bool check_2d_collision(actor_t *obj1, actor_t *obj2)
|
const bool check_2d_collision(actor_t *obj1, actor_t *obj2)
|
||||||
{
|
{
|
||||||
return (obj1->pos.x < obj2->pos.x + obj2->size.x) &&
|
return (obj1->pos.x < obj2->pos.x + obj2->size.x) &&
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ namespace actor
|
|||||||
// Torna un nou actor
|
// Torna un nou actor
|
||||||
actor_t *create(std::string name, vec3_t p, vec3_t s, std::string bmp, SDL_Rect r, SDL_Point o);
|
actor_t *create(std::string name, vec3_t p, vec3_t s, std::string bmp, SDL_Rect r, SDL_Point o);
|
||||||
|
|
||||||
|
void createFromFile(char **buffer);
|
||||||
|
|
||||||
void setDirty(actor_t *act, const bool force=false);
|
void setDirty(actor_t *act, const bool force=false);
|
||||||
|
|
||||||
void select(actor_t *act);
|
void select(actor_t *act);
|
||||||
|
|||||||
26
source/jutil.cpp
Normal file
26
source/jutil.cpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#include "jutil.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
int stringToInt(const char *value, std::vector<const char*> strings, std::vector<int> values)
|
||||||
|
{
|
||||||
|
char lowercase[255];
|
||||||
|
strcpy(lowercase, value);
|
||||||
|
for (int i=0; i<strlen(value);++i) lowercase[i]=tolower(value[i]);
|
||||||
|
|
||||||
|
const int max_size = strings.size()<values.size()?strings.size():values.size();
|
||||||
|
for (int i=0;i<max_size;++i)
|
||||||
|
{
|
||||||
|
if (strcmp(lowercase, strings[i])==0) return values[i];
|
||||||
|
}
|
||||||
|
return values[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool strcomp(const char *a, const char* b)
|
||||||
|
{
|
||||||
|
if (a==nullptr || b==nullptr) return false;
|
||||||
|
return (strcmp(a,b)==0);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
source/jutil.h
Normal file
9
source/jutil.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
int stringToInt(const char *value, std::vector<const char*> strings, std::vector<int> values);
|
||||||
|
|
||||||
|
const bool strcomp(const char *a, const char* b);
|
||||||
|
}
|
||||||
@@ -24,9 +24,12 @@ int room_walldoors = 0;
|
|||||||
|
|
||||||
std::vector<std::string> gifs;
|
std::vector<std::string> gifs;
|
||||||
|
|
||||||
|
bool editing = false;
|
||||||
|
|
||||||
void restart()
|
void restart()
|
||||||
{
|
{
|
||||||
room::load(room_w, room_h, room_xp, room_xn, room_yp, room_yn, room_color, room_floor, room_walls, room_doors, room_walldoors);
|
room::load(0); //room_w, room_h, room_xp, room_xn, room_yp, room_yn, room_color, room_floor, room_walls, room_doors, room_walldoors);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
box = actor::create("ASCENSOR",{16,32,0}, {8,8,4}, {64,0,32,24}, {0,24});
|
box = actor::create("ASCENSOR",{16,32,0}, {8,8,4}, {64,0,32,24}, {0,24});
|
||||||
@@ -115,7 +118,7 @@ void btn(const char* label, const int x, const int y, int &var, int min, int max
|
|||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
var=SDL_max(min, SDL_min(max, var-(result-2)));
|
var=SDL_max(min, SDL_min(max, var-(result-2)));
|
||||||
restart();
|
room::editor::setWidth(var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,11 +263,17 @@ bool game::loop()
|
|||||||
{
|
{
|
||||||
if (input::keyDown(SDL_SCANCODE_ESCAPE)) return false;
|
if (input::keyDown(SDL_SCANCODE_ESCAPE)) return false;
|
||||||
|
|
||||||
// WHILE EDITING...
|
|
||||||
//editor_move_selected();
|
|
||||||
//actor::updateEditor(actor::getFirst());
|
|
||||||
|
|
||||||
actor::update(actor::getFirst());
|
// WHILE EDITING...
|
||||||
|
if (editing)
|
||||||
|
{
|
||||||
|
editor_move_selected();
|
||||||
|
actor::updateEditor(actor::getFirst());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
actor::update(actor::getFirst());
|
||||||
|
}
|
||||||
|
|
||||||
actor::reorder();
|
actor::reorder();
|
||||||
|
|
||||||
|
|||||||
182
source/room.cpp
182
source/room.cpp
@@ -1,24 +1,31 @@
|
|||||||
#include "room.h"
|
#include "room.h"
|
||||||
#include "jdraw.h"
|
#include "jdraw.h"
|
||||||
|
#include "jfile.h"
|
||||||
|
#include "jutil.h"
|
||||||
#include "actor.h"
|
#include "actor.h"
|
||||||
|
|
||||||
namespace room
|
namespace room
|
||||||
{
|
{
|
||||||
static vec3_t size = {8,8,8};
|
static int inner_w = 2;
|
||||||
static vec3_t tmin = {0,0,0};
|
static int inner_h = 2;
|
||||||
static vec3_t tmax = {7,7,7};
|
|
||||||
static vec3_t min = {0,0,0};
|
|
||||||
static vec3_t max = {56,56,56};
|
|
||||||
|
|
||||||
static uint8_t doors = DOOR_XP /*| DOOR_YP*/ ;
|
static vec3_t size = {8,8,8}; // Tamany de l'habitació en tiles
|
||||||
static uint8_t door_height[4];
|
static vec3_t tmin = {0,0,0}; // primer tile en cada coordenada
|
||||||
static uint8_t color = 5;
|
static vec3_t tmax = {7,7,7}; // ultim tile en cada coordenada
|
||||||
|
static vec3_t min = {0,0,0}; // primer "pixel isometric" en cada coordenada
|
||||||
|
static vec3_t max = {56,56,56}; // ultim "pixel isometric" en cada coordenada
|
||||||
|
|
||||||
static uint8_t floor_type = 0;
|
static uint8_t doors = NO_DOOR; // Portes obertes
|
||||||
static uint8_t walls_type = 0;
|
static uint8_t door_height[4]; // Altura de cada porta
|
||||||
static uint8_t doors_type = 0;
|
static int8_t exits[6]; // Habitació destí a la que du cada porta (piso i sostre inclosos)
|
||||||
static uint8_t walldoors_type = 0;
|
static uint8_t color = 5; // Color de l'habitació
|
||||||
|
|
||||||
|
static uint8_t floor_type = 0; // Tile per al piso
|
||||||
|
static uint8_t walls_type = 0; // Tile per a les pareds
|
||||||
|
static uint8_t doors_type = 0; // Textura per a les portes
|
||||||
|
static uint8_t walldoors_type = 0; // Textura per a baix de les portes
|
||||||
|
|
||||||
|
// Surface on se guarden els gràfics de cada cosa
|
||||||
static draw::surface *floor_surf = nullptr;
|
static draw::surface *floor_surf = nullptr;
|
||||||
static draw::surface *walls_surf = nullptr;
|
static draw::surface *walls_surf = nullptr;
|
||||||
static draw::surface *doors_surf = nullptr;
|
static draw::surface *doors_surf = nullptr;
|
||||||
@@ -28,6 +35,8 @@ namespace room
|
|||||||
{
|
{
|
||||||
actor::clear();
|
actor::clear();
|
||||||
|
|
||||||
|
// [TODO][2024-06-05] Açò es una xorrada. Si al final sempre son els mateixos arxius,
|
||||||
|
// carregar açò al principi del joc i au
|
||||||
if (floor_surf) draw::freeSurface(floor_surf);
|
if (floor_surf) draw::freeSurface(floor_surf);
|
||||||
if (walls_surf) draw::freeSurface(walls_surf);
|
if (walls_surf) draw::freeSurface(walls_surf);
|
||||||
if (doors_surf) draw::freeSurface(doors_surf);
|
if (doors_surf) draw::freeSurface(doors_surf);
|
||||||
@@ -39,24 +48,18 @@ namespace room
|
|||||||
aux_surf = draw::loadSurface("roomaux.gif");
|
aux_surf = draw::loadSurface("roomaux.gif");
|
||||||
}
|
}
|
||||||
|
|
||||||
void load(int x, int y, int8_t xp, int8_t xn, int8_t yp, int8_t yn, uint8_t col, uint8_t floor, uint8_t walls, uint8_t door, uint8_t walldoor)
|
void refresh()
|
||||||
{
|
{
|
||||||
init();
|
size = {(inner_w+1)*2,(inner_h+1)*2,3};
|
||||||
color = col;
|
tmin = {3-inner_w,3-inner_h,0};
|
||||||
floor_type = floor;
|
tmax = {4+inner_w,4+inner_h,3};
|
||||||
walls_type = walls;
|
|
||||||
doors_type = door;
|
|
||||||
walldoors_type = walldoor;
|
|
||||||
size = {(x+1)*2,(y+1)*2,3};
|
|
||||||
tmin = {3-x,3-y,0};
|
|
||||||
tmax = {4+x,4+y,3};
|
|
||||||
min = {tmin.x*8,tmin.y*8,0};
|
min = {tmin.x*8,tmin.y*8,0};
|
||||||
max = {tmax.x*8,tmax.y*8,24};
|
max = {tmax.x*8,tmax.y*8,24};
|
||||||
doors = (xp>=0?DOOR_XP:0) | (xn>=0?DOOR_XN:0) | (yp>=0?DOOR_YP:0) | (yn>=0?DOOR_YN:0);
|
doors = (door_height[XP]>=0?DOOR_XP:0) | (door_height[XN]>=0?DOOR_XN:0) | (door_height[YP]>=0?DOOR_YP:0) | (door_height[YN]>=0?DOOR_YN:0);
|
||||||
door_height[0] = xp; //XP
|
//door_height[0] = inner_xp; //XP
|
||||||
door_height[1] = xn; //XN
|
//door_height[1] = inner_xn; //XN
|
||||||
door_height[2] = yp; //YP
|
//door_height[2] = inner_yp; //YP
|
||||||
door_height[3] = yn; //YN
|
//door_height[3] = inner_yn; //YN
|
||||||
|
|
||||||
if (doors & DOOR_YP)
|
if (doors & DOOR_YP)
|
||||||
{
|
{
|
||||||
@@ -83,6 +86,104 @@ namespace room
|
|||||||
actor::reorder();
|
actor::reorder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//void load(int x, int y, int8_t xp, int8_t xn, int8_t yp, int8_t yn, uint8_t col, uint8_t floor, uint8_t walls, uint8_t door, uint8_t walldoor)
|
||||||
|
void load(const int room)
|
||||||
|
{
|
||||||
|
if (room > 64) { perror("ERROR: Nombre d'habitació massa gran! Eixint..."); exit(1); }
|
||||||
|
init();
|
||||||
|
|
||||||
|
// Primer carreguem els valors per defecte
|
||||||
|
inner_w = inner_h = 2;
|
||||||
|
for (int i=0;i<4;++i) door_height[i] = -1;
|
||||||
|
color = 9;
|
||||||
|
floor_type = walls_type = doors_type = walldoors_type = 0;
|
||||||
|
for (int i=0;i<6;++i) exits[i] = -1;
|
||||||
|
|
||||||
|
// Després intentem carregar els valors segons el arxiu que toca, si existeix
|
||||||
|
char filename[] = "rooms/00.txt";
|
||||||
|
filename[6] = int(room/10)*48;
|
||||||
|
filename[7] = (room%10)*48;
|
||||||
|
int filesize=0;
|
||||||
|
char *buffer = file::getFileBuffer(filename, filesize, true);
|
||||||
|
char *original_buffer = buffer;
|
||||||
|
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
while (*buffer != 0)
|
||||||
|
{
|
||||||
|
const char* key = file::readString(&buffer);
|
||||||
|
|
||||||
|
if (util::strcomp(key, "width:")) {
|
||||||
|
const int val = file::readInt(&buffer);
|
||||||
|
inner_w = SDL_clamp(val, 0, 3);
|
||||||
|
} else if (util::strcomp(key, "height:")) {
|
||||||
|
const int val = file::readInt(&buffer);
|
||||||
|
inner_h = SDL_clamp(val, 0, 3);
|
||||||
|
|
||||||
|
} else if (util::strcomp(key, "door-height-xp:")) {
|
||||||
|
const int val = file::readInt(&buffer);
|
||||||
|
door_height[XP] = SDL_clamp(val, -1, 5);
|
||||||
|
} else if (util::strcomp(key, "door-height-xn:")) {
|
||||||
|
const int val = file::readInt(&buffer);
|
||||||
|
door_height[XN] = SDL_clamp(val, -1, 5);
|
||||||
|
} else if (util::strcomp(key, "door-height-yp:")) {
|
||||||
|
const int val = file::readInt(&buffer);
|
||||||
|
door_height[YP] = SDL_clamp(val, -1, 5);
|
||||||
|
} else if (util::strcomp(key, "door-height-yn:")) {
|
||||||
|
const int val = file::readInt(&buffer);
|
||||||
|
door_height[YN] = SDL_clamp(val, -1, 5);
|
||||||
|
|
||||||
|
} else if (util::strcomp(key, "color:")) {
|
||||||
|
color = util::stringToInt(file::readString(&buffer), {"blue", "red", "purple", "green", "cyan", "yellow", "white"}, {5, 6, 7, 8, 9, 10, 11});
|
||||||
|
|
||||||
|
} else if (util::strcomp(key, "floor-texture:")) {
|
||||||
|
floor_type = file::readInt(&buffer);
|
||||||
|
} else if (util::strcomp(key, "wall-texture:")) {
|
||||||
|
walls_type = file::readInt(&buffer);
|
||||||
|
} else if (util::strcomp(key, "door-texture:")) {
|
||||||
|
doors_type = file::readInt(&buffer);
|
||||||
|
} else if (util::strcomp(key, "under-door-texture:")) {
|
||||||
|
walldoors_type = file::readInt(&buffer);
|
||||||
|
|
||||||
|
} else if (util::strcomp(key, "exit-xp:")) {
|
||||||
|
const int val = file::readInt(&buffer);
|
||||||
|
exits[0] = SDL_clamp(val, 0, 64);
|
||||||
|
} else if (util::strcomp(key, "exit-xn:")) {
|
||||||
|
const int val = file::readInt(&buffer);
|
||||||
|
exits[1] = SDL_clamp(val, 0, 64);
|
||||||
|
} else if (util::strcomp(key, "exit-yp:")) {
|
||||||
|
const int val = file::readInt(&buffer);
|
||||||
|
exits[2] = SDL_clamp(val, 0, 64);
|
||||||
|
} else if (util::strcomp(key, "exit-yn:")) {
|
||||||
|
const int val = file::readInt(&buffer);
|
||||||
|
exits[3] = SDL_clamp(val, 0, 64);
|
||||||
|
} else if (util::strcomp(key, "exit-zp:")) {
|
||||||
|
const int val = file::readInt(&buffer);
|
||||||
|
exits[4] = SDL_clamp(val, 0, 64);
|
||||||
|
} else if (util::strcomp(key, "exit-zn:")) {
|
||||||
|
const int val = file::readInt(&buffer);
|
||||||
|
exits[5] = SDL_clamp(val, 0, 64);
|
||||||
|
|
||||||
|
} else if (util::strcomp(key, "actor{")) {
|
||||||
|
actor::createFromFile(&buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(original_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update()
|
||||||
|
{
|
||||||
|
actor::remove(actor::find("DOOR_XP1"));
|
||||||
|
actor::remove(actor::find("DOOR_XP2"));
|
||||||
|
actor::remove(actor::find("DOOR_YP1"));
|
||||||
|
actor::remove(actor::find("DOOR_YP2"));
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
void draw()
|
void draw()
|
||||||
{
|
{
|
||||||
draw::pushSource();
|
draw::pushSource();
|
||||||
@@ -232,4 +333,31 @@ namespace room
|
|||||||
{
|
{
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace editor
|
||||||
|
{
|
||||||
|
void setWidth(const int value) { inner_w = value; update(); }
|
||||||
|
void setHeight(const int value) { inner_h = value; update(); }
|
||||||
|
void setDoor(const int which, const int value) { door_height[which] = value; update(); }
|
||||||
|
|
||||||
|
void setColor(const int value) { color = value; update(); }
|
||||||
|
void setFloorTex(const int value) { floor_type = value; update(); }
|
||||||
|
void setWallTex(const int value) { walls_type = value; update(); }
|
||||||
|
void setDoorTex(const int value) { doors_type = value; update(); }
|
||||||
|
void setWallDoorTex(const int value) { walldoors_type = value; update(); }
|
||||||
|
void setExit(const int which, const int value) { exits[which] = value; update(); }
|
||||||
|
|
||||||
|
const int getWidth() { return inner_w; }
|
||||||
|
const int getHeight() { return inner_h; }
|
||||||
|
const int getDoor(const int which) { return door_height[which]; }
|
||||||
|
|
||||||
|
const int getColor() { return color; }
|
||||||
|
const int getFloorTex() { return floor_type; }
|
||||||
|
const int getWallTex() { return walls_type; }
|
||||||
|
const int getDoorTex() { return doors_type; }
|
||||||
|
const int getWallDoorTex() { return walldoors_type; }
|
||||||
|
|
||||||
|
const int getExit(const int which) { return exits[which]; }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
|
#define NO_DOOR 0
|
||||||
#define DOOR_XP 1
|
#define DOOR_XP 1
|
||||||
#define DOOR_XN 2
|
#define DOOR_XN 2
|
||||||
#define DOOR_YP 4
|
#define DOOR_YP 4
|
||||||
@@ -10,11 +11,14 @@
|
|||||||
#define XN 1
|
#define XN 1
|
||||||
#define YP 2
|
#define YP 2
|
||||||
#define YN 3
|
#define YN 3
|
||||||
|
#define ZP 4
|
||||||
|
#define ZN 5
|
||||||
|
|
||||||
namespace room
|
namespace room
|
||||||
{
|
{
|
||||||
void init();
|
void init();
|
||||||
void load(int x, int y, int8_t xp, int8_t xn, int8_t yp, int8_t yn, uint8_t col, uint8_t floor, uint8_t walls, uint8_t door, uint8_t doorwall);
|
void load(const int room);
|
||||||
|
//void load(int x, int y, int8_t xp, int8_t xn, int8_t yp, int8_t yn, uint8_t col, uint8_t floor, uint8_t walls, uint8_t door, uint8_t doorwall);
|
||||||
void draw();
|
void draw();
|
||||||
void draw2();
|
void draw2();
|
||||||
|
|
||||||
@@ -24,4 +28,31 @@ namespace room
|
|||||||
uint8_t getDoors();
|
uint8_t getDoors();
|
||||||
uint8_t getDoor(const int d);
|
uint8_t getDoor(const int d);
|
||||||
uint8_t getColor();
|
uint8_t getColor();
|
||||||
|
|
||||||
|
namespace editor
|
||||||
|
{
|
||||||
|
void setWidth(const int value);
|
||||||
|
void setHeight(const int value);
|
||||||
|
void setDoor(const int which, const int value);
|
||||||
|
|
||||||
|
void setColor(const int value);
|
||||||
|
void setFloorTex(const int value);
|
||||||
|
void setWallTex(const int value);
|
||||||
|
void setDoorTex(const int value);
|
||||||
|
void setWallDoorTex(const int value);
|
||||||
|
|
||||||
|
void setExit(const int which, const int value);
|
||||||
|
|
||||||
|
const int getWidth();
|
||||||
|
const int getHeight();
|
||||||
|
const int getDoor(const int which);
|
||||||
|
|
||||||
|
const int getColor();
|
||||||
|
const int getFloorTex();
|
||||||
|
const int getWallTex();
|
||||||
|
const int getDoorTex();
|
||||||
|
const int getWallDoorTex();
|
||||||
|
|
||||||
|
const int getExit(const int which);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user