planes
This commit is contained in:
parent
c9e48fb17b
commit
e02404222d
|
@ -60,6 +60,7 @@ enum FurnaceCVObjectTypes {
|
||||||
CV_ENEMY_BOMB,
|
CV_ENEMY_BOMB,
|
||||||
CV_EXPLOSION,
|
CV_EXPLOSION,
|
||||||
CV_ENEMY,
|
CV_ENEMY,
|
||||||
|
CV_PLANE,
|
||||||
CV_FURBALL,
|
CV_FURBALL,
|
||||||
CV_MINE,
|
CV_MINE,
|
||||||
CV_POWERUP_P,
|
CV_POWERUP_P,
|
||||||
|
@ -111,6 +112,135 @@ void FurnaceCVObject::collision(FurnaceCVObject* other) {
|
||||||
void FurnaceCVObject::tick() {
|
void FurnaceCVObject::tick() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct FurnaceCV {
|
||||||
|
SDL_Surface* surface;
|
||||||
|
unsigned char* prioBuf;
|
||||||
|
DivEngine* e;
|
||||||
|
unsigned char* tileData;
|
||||||
|
unsigned int tick;
|
||||||
|
|
||||||
|
// state
|
||||||
|
unsigned short* curStage;
|
||||||
|
int stageWidth, stageHeight;
|
||||||
|
int stageWidthPx, stageHeightPx;
|
||||||
|
|
||||||
|
const char* typeAddr;
|
||||||
|
unsigned char typeDelay;
|
||||||
|
int typeX, typeY;
|
||||||
|
int typeXStart, typeYStart;
|
||||||
|
int typeXEnd, typeYEnd;
|
||||||
|
|
||||||
|
int textWait, curText, transWait;
|
||||||
|
int ticksToInit;
|
||||||
|
|
||||||
|
bool inGame, inTransition, newHiScore, playSongs, pleaseInitSongs, gameOver;
|
||||||
|
unsigned char lives, respawnTime, stage, shotType;
|
||||||
|
int score;
|
||||||
|
int hiScore;
|
||||||
|
short lastPlayerX, lastPlayerY;
|
||||||
|
short fxChanBase, fxInsBase;
|
||||||
|
short speedTicks;
|
||||||
|
short planeTime;
|
||||||
|
float origSongRate;
|
||||||
|
|
||||||
|
FixedQueue<unsigned char,16> weaponStack;
|
||||||
|
|
||||||
|
// graphics
|
||||||
|
unsigned short tile0[56][80];
|
||||||
|
unsigned short tile1[56][80];
|
||||||
|
unsigned short scrollX[2];
|
||||||
|
unsigned short scrollY[2];
|
||||||
|
unsigned char bgColor;
|
||||||
|
std::vector<FurnaceCVObject*> sprite;
|
||||||
|
// this offset is applied to sprites.
|
||||||
|
int viewX, viewY;
|
||||||
|
|
||||||
|
// input
|
||||||
|
unsigned char joyInputPrev;
|
||||||
|
unsigned char joyPressed;
|
||||||
|
unsigned char joyReleased;
|
||||||
|
unsigned char joyInput;
|
||||||
|
|
||||||
|
template<typename T> T* createObject(short x=0, short y=0);
|
||||||
|
template<typename T> T* createObjectNoPos();
|
||||||
|
void buildStage(int which);
|
||||||
|
|
||||||
|
void putText(int fontBase, bool fontHeight, String text, int x, int y);
|
||||||
|
|
||||||
|
void startTyping(const char* text, int x, int y);
|
||||||
|
|
||||||
|
void soundEffect(int ins, int chan, int note);
|
||||||
|
void stopSoundEffect(int ins, int chan, int note);
|
||||||
|
|
||||||
|
void addScore(int amount);
|
||||||
|
|
||||||
|
void typeTick();
|
||||||
|
|
||||||
|
void rasterH(int scanline);
|
||||||
|
void render(unsigned char joyIn);
|
||||||
|
void tileDataRead(struct GIF_WHDR* data);
|
||||||
|
void loadInstruments();
|
||||||
|
bool init(DivEngine* eng);
|
||||||
|
void unload();
|
||||||
|
|
||||||
|
FurnaceCV():
|
||||||
|
surface(NULL),
|
||||||
|
e(NULL),
|
||||||
|
tileData(NULL),
|
||||||
|
tick(0),
|
||||||
|
curStage(NULL),
|
||||||
|
stageWidth(40),
|
||||||
|
stageHeight(28),
|
||||||
|
stageWidthPx(320),
|
||||||
|
stageHeightPx(224),
|
||||||
|
typeAddr(NULL),
|
||||||
|
typeDelay(0),
|
||||||
|
typeX(0),
|
||||||
|
typeY(0),
|
||||||
|
typeXStart(0),
|
||||||
|
typeYStart(0),
|
||||||
|
typeXEnd(39),
|
||||||
|
typeYEnd(27),
|
||||||
|
textWait(60),
|
||||||
|
curText(0),
|
||||||
|
transWait(0),
|
||||||
|
ticksToInit(2),
|
||||||
|
inGame(false),
|
||||||
|
inTransition(false),
|
||||||
|
newHiScore(false),
|
||||||
|
playSongs(true),
|
||||||
|
pleaseInitSongs(false),
|
||||||
|
gameOver(false),
|
||||||
|
lives(5),
|
||||||
|
respawnTime(0),
|
||||||
|
stage(0),
|
||||||
|
shotType(0),
|
||||||
|
score(0),
|
||||||
|
hiScore(25000),
|
||||||
|
lastPlayerX(0),
|
||||||
|
lastPlayerY(0),
|
||||||
|
fxChanBase(-1),
|
||||||
|
fxInsBase(-1),
|
||||||
|
speedTicks(0),
|
||||||
|
planeTime(0),
|
||||||
|
origSongRate(60.0f),
|
||||||
|
bgColor(0),
|
||||||
|
viewX(0),
|
||||||
|
viewY(0),
|
||||||
|
joyInputPrev(0),
|
||||||
|
joyPressed(0),
|
||||||
|
joyReleased(0),
|
||||||
|
joyInput(0) {
|
||||||
|
memset(tile0,0,80*56*sizeof(short));
|
||||||
|
memset(tile1,0,80*56*sizeof(short));
|
||||||
|
|
||||||
|
scrollX[0]=0;
|
||||||
|
scrollX[1]=0;
|
||||||
|
scrollY[0]=0;
|
||||||
|
scrollY[1]=0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct FurnaceCVPlayer: FurnaceCVObject {
|
struct FurnaceCVPlayer: FurnaceCVObject {
|
||||||
short subX, subY;
|
short subX, subY;
|
||||||
short speedX, speedY;
|
short speedX, speedY;
|
||||||
|
@ -255,6 +385,7 @@ struct FurnaceCVEnemyVortex: FurnaceCVObject {
|
||||||
speedX((rand()%5)-2),
|
speedX((rand()%5)-2),
|
||||||
speedY((rand()%5)-2) {
|
speedY((rand()%5)-2) {
|
||||||
type=CV_ENEMY;
|
type=CV_ENEMY;
|
||||||
|
prio=2;
|
||||||
spriteDef[0]=0x480;
|
spriteDef[0]=0x480;
|
||||||
spriteDef[1]=0x481;
|
spriteDef[1]=0x481;
|
||||||
spriteDef[2]=0x4a0;
|
spriteDef[2]=0x4a0;
|
||||||
|
@ -262,6 +393,66 @@ struct FurnaceCVEnemyVortex: FurnaceCVObject {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FurnaceCVEnemyPlane: FurnaceCVObject {
|
||||||
|
unsigned char orient;
|
||||||
|
short shootTime, speed;
|
||||||
|
|
||||||
|
void collision(FurnaceCVObject* other);
|
||||||
|
|
||||||
|
void tick();
|
||||||
|
FurnaceCVEnemyPlane(FurnaceCV* p):
|
||||||
|
FurnaceCVObject(p),
|
||||||
|
orient(rand()&3),
|
||||||
|
shootTime(40),
|
||||||
|
speed(3) {
|
||||||
|
type=CV_PLANE;
|
||||||
|
speed=2+(p->stage>>2)+(rand()%3);
|
||||||
|
prio=3;
|
||||||
|
if (speed>8) speed=8;
|
||||||
|
switch (orient) {
|
||||||
|
case 0: case 2:
|
||||||
|
spriteWidth=8;
|
||||||
|
spriteHeight=5;
|
||||||
|
break;
|
||||||
|
case 1: case 3:
|
||||||
|
spriteWidth=5;
|
||||||
|
spriteHeight=8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (orient) {
|
||||||
|
case 0:
|
||||||
|
for (int i=0; i<40; i++) {
|
||||||
|
spriteDef[i]=0x4c0+(i&7)+((i>>3)<<5);
|
||||||
|
}
|
||||||
|
x=-80;
|
||||||
|
y=rand()%(p->stageHeightPx-80);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
for (int i=0; i<40; i++) {
|
||||||
|
spriteDef[i]=0x4d7+(i%5)+((i/5)<<5);
|
||||||
|
}
|
||||||
|
x=rand()%(p->stageWidthPx-80);
|
||||||
|
y=p->stageHeightPx+16;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
for (int i=0; i<40; i++) {
|
||||||
|
spriteDef[i]=0x4c9+(i&7)+((i>>3)<<5);
|
||||||
|
}
|
||||||
|
x=p->stageWidthPx+16;
|
||||||
|
y=rand()%(p->stageHeightPx-80);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
for (int i=0; i<40; i++) {
|
||||||
|
spriteDef[i]=0x4d2+(i%5)+((i/5)<<5);
|
||||||
|
}
|
||||||
|
x=rand()%(p->stageWidthPx-80);
|
||||||
|
y=-80;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct FurnaceCVExplTiny: FurnaceCVObject {
|
struct FurnaceCVExplTiny: FurnaceCVObject {
|
||||||
unsigned char animFrame;
|
unsigned char animFrame;
|
||||||
|
|
||||||
|
@ -412,132 +603,6 @@ struct FurnaceCVExtraLife: FurnaceCVObject {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FurnaceCV {
|
|
||||||
SDL_Surface* surface;
|
|
||||||
unsigned char* prioBuf;
|
|
||||||
DivEngine* e;
|
|
||||||
unsigned char* tileData;
|
|
||||||
unsigned int tick;
|
|
||||||
|
|
||||||
// state
|
|
||||||
unsigned short* curStage;
|
|
||||||
int stageWidth, stageHeight;
|
|
||||||
int stageWidthPx, stageHeightPx;
|
|
||||||
|
|
||||||
const char* typeAddr;
|
|
||||||
unsigned char typeDelay;
|
|
||||||
int typeX, typeY;
|
|
||||||
int typeXStart, typeYStart;
|
|
||||||
int typeXEnd, typeYEnd;
|
|
||||||
|
|
||||||
int textWait, curText, transWait;
|
|
||||||
int ticksToInit;
|
|
||||||
|
|
||||||
bool inGame, inTransition, newHiScore, playSongs, pleaseInitSongs, gameOver;
|
|
||||||
unsigned char lives, respawnTime, stage, shotType;
|
|
||||||
int score;
|
|
||||||
int hiScore;
|
|
||||||
short lastPlayerX, lastPlayerY;
|
|
||||||
short fxChanBase, fxInsBase;
|
|
||||||
short speedTicks;
|
|
||||||
float origSongRate;
|
|
||||||
|
|
||||||
FixedQueue<unsigned char,16> weaponStack;
|
|
||||||
|
|
||||||
// graphics
|
|
||||||
unsigned short tile0[56][80];
|
|
||||||
unsigned short tile1[56][80];
|
|
||||||
unsigned short scrollX[2];
|
|
||||||
unsigned short scrollY[2];
|
|
||||||
unsigned char bgColor;
|
|
||||||
std::vector<FurnaceCVObject*> sprite;
|
|
||||||
// this offset is applied to sprites.
|
|
||||||
int viewX, viewY;
|
|
||||||
|
|
||||||
// input
|
|
||||||
unsigned char joyInputPrev;
|
|
||||||
unsigned char joyPressed;
|
|
||||||
unsigned char joyReleased;
|
|
||||||
unsigned char joyInput;
|
|
||||||
|
|
||||||
template<typename T> T* createObject(short x=0, short y=0);
|
|
||||||
void buildStage(int which);
|
|
||||||
|
|
||||||
void putText(int fontBase, bool fontHeight, String text, int x, int y);
|
|
||||||
|
|
||||||
void startTyping(const char* text, int x, int y);
|
|
||||||
|
|
||||||
void soundEffect(int ins, int chan, int note);
|
|
||||||
void stopSoundEffect(int ins, int chan, int note);
|
|
||||||
|
|
||||||
void addScore(int amount);
|
|
||||||
|
|
||||||
void typeTick();
|
|
||||||
|
|
||||||
void rasterH(int scanline);
|
|
||||||
void render(unsigned char joyIn);
|
|
||||||
void tileDataRead(struct GIF_WHDR* data);
|
|
||||||
void loadInstruments();
|
|
||||||
bool init(DivEngine* eng);
|
|
||||||
void unload();
|
|
||||||
|
|
||||||
FurnaceCV():
|
|
||||||
surface(NULL),
|
|
||||||
e(NULL),
|
|
||||||
tileData(NULL),
|
|
||||||
tick(0),
|
|
||||||
curStage(NULL),
|
|
||||||
stageWidth(40),
|
|
||||||
stageHeight(28),
|
|
||||||
stageWidthPx(320),
|
|
||||||
stageHeightPx(224),
|
|
||||||
typeAddr(NULL),
|
|
||||||
typeDelay(0),
|
|
||||||
typeX(0),
|
|
||||||
typeY(0),
|
|
||||||
typeXStart(0),
|
|
||||||
typeYStart(0),
|
|
||||||
typeXEnd(39),
|
|
||||||
typeYEnd(27),
|
|
||||||
textWait(60),
|
|
||||||
curText(0),
|
|
||||||
transWait(0),
|
|
||||||
ticksToInit(2),
|
|
||||||
inGame(false),
|
|
||||||
inTransition(false),
|
|
||||||
newHiScore(false),
|
|
||||||
playSongs(true),
|
|
||||||
pleaseInitSongs(false),
|
|
||||||
gameOver(false),
|
|
||||||
lives(5),
|
|
||||||
respawnTime(0),
|
|
||||||
stage(0),
|
|
||||||
shotType(0),
|
|
||||||
score(0),
|
|
||||||
hiScore(25000),
|
|
||||||
lastPlayerX(0),
|
|
||||||
lastPlayerY(0),
|
|
||||||
fxChanBase(-1),
|
|
||||||
fxInsBase(-1),
|
|
||||||
speedTicks(0),
|
|
||||||
origSongRate(60.0f),
|
|
||||||
bgColor(0),
|
|
||||||
viewX(0),
|
|
||||||
viewY(0),
|
|
||||||
joyInputPrev(0),
|
|
||||||
joyPressed(0),
|
|
||||||
joyReleased(0),
|
|
||||||
joyInput(0) {
|
|
||||||
memset(tile0,0,80*56*sizeof(short));
|
|
||||||
memset(tile1,0,80*56*sizeof(short));
|
|
||||||
|
|
||||||
scrollX[0]=0;
|
|
||||||
scrollX[1]=0;
|
|
||||||
scrollY[0]=0;
|
|
||||||
scrollY[1]=0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char* cvText[]={
|
static const char* cvText[]={
|
||||||
// intro
|
// intro
|
||||||
_N("Play demo songs?\n"
|
_N("Play demo songs?\n"
|
||||||
|
@ -787,33 +852,33 @@ void FurnaceGUI::drawTutorial() {
|
||||||
ImGui::SetNextWindowPos(ImVec2(0,0));
|
ImGui::SetNextWindowPos(ImVec2(0,0));
|
||||||
ImGui::SetNextWindowSize(ImVec2(canvasW,canvasH));
|
ImGui::SetNextWindowSize(ImVec2(canvasW,canvasH));
|
||||||
if (ImGui::Begin("Combat Vehicle",&cvOpen,ImGuiWindowFlags_NoDocking|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_Modal|ImGuiWindowFlags_NoTitleBar)) {
|
if (ImGui::Begin("Combat Vehicle",&cvOpen,ImGuiWindowFlags_NoDocking|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_Modal|ImGuiWindowFlags_NoTitleBar)) {
|
||||||
ImVec2 dpadLoc=ImVec2(canvasW*0.25,canvasH*0.85);
|
ImVec2 dpadLoc=ImVec2(canvasW*0.22,canvasH*0.85);
|
||||||
ImVec2 buttonLoc=ImVec2(canvasW*0.75,canvasH*0.85);
|
ImVec2 buttonLoc=ImVec2(canvasW*0.78,canvasH*0.85);
|
||||||
float oneUnit=canvasW*0.15;
|
float oneUnit=canvasW*0.12;
|
||||||
|
|
||||||
ImVec2 dpadUpStart=ImVec2(
|
ImVec2 dpadUpStart=ImVec2(
|
||||||
dpadLoc.x-oneUnit*1.5,
|
dpadLoc.x-oneUnit*1.75,
|
||||||
dpadLoc.y-oneUnit*1.5
|
dpadLoc.y-oneUnit*1.75
|
||||||
);
|
);
|
||||||
ImVec2 dpadUpEnd=ImVec2(
|
ImVec2 dpadUpEnd=ImVec2(
|
||||||
dpadLoc.x+oneUnit*1.5,
|
dpadLoc.x+oneUnit*1.75,
|
||||||
dpadLoc.y-oneUnit*0.5
|
dpadLoc.y-oneUnit*0.5
|
||||||
);
|
);
|
||||||
ImVec2 dpadLeftEnd=ImVec2(
|
ImVec2 dpadLeftEnd=ImVec2(
|
||||||
dpadLoc.x-oneUnit*0.5,
|
dpadLoc.x-oneUnit*0.5,
|
||||||
dpadLoc.y+oneUnit*1.5
|
dpadLoc.y+oneUnit*1.75
|
||||||
);
|
);
|
||||||
ImVec2 dpadDownStart=ImVec2(
|
ImVec2 dpadDownStart=ImVec2(
|
||||||
dpadLoc.x-oneUnit*1.5,
|
dpadLoc.x-oneUnit*1.75,
|
||||||
dpadLoc.y+oneUnit*0.5
|
dpadLoc.y+oneUnit*0.5
|
||||||
);
|
);
|
||||||
ImVec2 dpadDownEnd=ImVec2(
|
ImVec2 dpadDownEnd=ImVec2(
|
||||||
dpadLoc.x+oneUnit*1.5,
|
dpadLoc.x+oneUnit*1.75,
|
||||||
dpadLoc.y+oneUnit*1.5
|
dpadLoc.y+oneUnit*1.75
|
||||||
);
|
);
|
||||||
ImVec2 dpadRightStart=ImVec2(
|
ImVec2 dpadRightStart=ImVec2(
|
||||||
dpadLoc.x+oneUnit*0.5,
|
dpadLoc.x+oneUnit*0.5,
|
||||||
dpadLoc.y-oneUnit*1.5
|
dpadLoc.y-oneUnit*1.75
|
||||||
);
|
);
|
||||||
|
|
||||||
ImVec2 buttonBStart=ImVec2(
|
ImVec2 buttonBStart=ImVec2(
|
||||||
|
@ -875,6 +940,7 @@ void FurnaceGUI::drawTutorial() {
|
||||||
delete cv;
|
delete cv;
|
||||||
cv=NULL;
|
cv=NULL;
|
||||||
cvOpen=false;
|
cvOpen=false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1110,6 +1176,12 @@ template<typename T> T* FurnaceCV::createObject(short x, short y) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T> T* FurnaceCV::createObjectNoPos() {
|
||||||
|
T* ret=new T(this);
|
||||||
|
sprite.push_back(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void FurnaceCV::soundEffect(int ins, int chan, int note) {
|
void FurnaceCV::soundEffect(int ins, int chan, int note) {
|
||||||
e->noteOn(chan+fxChanBase,ins+fxInsBase,note);
|
e->noteOn(chan+fxChanBase,ins+fxInsBase,note);
|
||||||
/*
|
/*
|
||||||
|
@ -1293,6 +1365,9 @@ void FurnaceCV::buildStage(int which) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setup stuff
|
||||||
|
planeTime=180+(rand()%400);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CV_FONTBASE_8x8 0x250
|
#define CV_FONTBASE_8x8 0x250
|
||||||
|
@ -1411,6 +1486,15 @@ void FurnaceCV::render(unsigned char joyIn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inGame) {
|
if (inGame) {
|
||||||
|
// planes
|
||||||
|
if (--planeTime<=0) {
|
||||||
|
planeTime=MAX(10,60-(stage*2))+(rand()%MAX(50,320-stage*4));
|
||||||
|
if (stage>=5 && stage!=9 && (stage&1 || stage>=10)) {
|
||||||
|
createObjectNoPos<FurnaceCVEnemyPlane>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialization
|
||||||
if (ticksToInit>0) {
|
if (ticksToInit>0) {
|
||||||
if (--ticksToInit<1) {
|
if (--ticksToInit<1) {
|
||||||
e->changeSongP(0);
|
e->changeSongP(0);
|
||||||
|
@ -3169,3 +3253,41 @@ void FurnaceCVEnemyVortex::tick() {
|
||||||
spriteDef[2]=0x4a0+((animFrame>>5)<<1);
|
spriteDef[2]=0x4a0+((animFrame>>5)<<1);
|
||||||
spriteDef[3]=0x4a1+((animFrame>>5)<<1);
|
spriteDef[3]=0x4a1+((animFrame>>5)<<1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FurnaceCVEnemyPlane IMPLEMENTATION
|
||||||
|
|
||||||
|
void FurnaceCVEnemyPlane::collision(FurnaceCVObject* other) {
|
||||||
|
// ignore completely
|
||||||
|
}
|
||||||
|
|
||||||
|
void FurnaceCVEnemyPlane::tick() {
|
||||||
|
switch (orient) {
|
||||||
|
case 0:
|
||||||
|
x+=speed;
|
||||||
|
if (x>cv->stageWidthPx+32) dead=true;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
y-=speed;
|
||||||
|
if (y<-160) dead=true;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
x-=speed;
|
||||||
|
if (x<-160) dead=true;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
y+=speed;
|
||||||
|
if (y>cv->stageHeightPx+32) dead=true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dead=true;
|
||||||
|
logE("plane with invalid orientation %d",orient);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dead) logE("plane dead");
|
||||||
|
|
||||||
|
if (--shootTime<=0) {
|
||||||
|
shootTime=40;
|
||||||
|
//cv->soundEffect(SE_VORTEXSHOOT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue