PieceOpt.push_back(p.GetHash());
++tot;
}
sort(PieceOpt.begin(), PieceOpt.end());
for (llu o : PieceOpt) res=res*37LLU+o;
/*for (Piece p : Next) {
if (tot) --tot;
else res=res*47LL+p.GetHash();
}*/
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
res*=47LLU; if (B[i][j]) ++res;
}
}
return res;
}
~Status() {
for (int i=0; i<=LX+1; ++i) delete[] B[i];
delete[] B;
}
};
struct Particle {
double x, y, vx, vy, ax, ay;
double sz, dsz, th, dth; int n, clr;
void Update(int TimeDel) {
vx += double(TimeDel)*0.001*ax;
vy += double(TimeDel)*0.001*ay;
x += double(TimeDel)*0.001*vx;
y += double(TimeDel)*0.001*vy;
sz = max(0.0,sz-double(TimeDel)*0.001*dsz);
th += double(TimeDel)*0.001*dth;
}
};
struct FloatText {
double x, y, vx, vy, ax, ay, sz, dsz, bd, dbd;
double th, dth, w, dw;
int clr; string Text;
void Update(int TimeDel) {
vx += double(TimeDel)*0.001*ax;
vy += double(TimeDel)*0.001*ay;
x += double(TimeDel)*0.001*vx;
y += double(TimeDel)*0.001*vy;
sz = max(0.0,sz-double(TimeDel)*0.001*dsz);
bd = max(0.0,bd-double(TimeDel)*0.001*dbd);
th += double(TimeDel)*0.001*dth;
w += double(TimeDel)*0.001*dw;
}
};
struct GarbageLayer {
vector<int> B;
int Delay;
GarbageLayer(int LY=0, int _Delay=0) {
B.resize(LY+2,0); Delay=_Delay;
}
};
string Menu = "home";
bool Pause = false;
bool ShowAttack = false;
const int Max = 9999999;
int FrameAILimit = 1;
double CurX, CurY;
int PlayerCount, AliveCount;
set<llu> InList;
struct BoardHistory {
int SX, LX, LY, TargetSta; vector<vector<int> > B, U;
PieceGenerator Gen; Piece Cur; vector<Piece> Hold, Next;
vector<GarbageLayer> AttackIn;
int TPiece, TLine, TDig, TAttack, TAC, Combo, B2B, C2ComboRem;
bool CurClutch;
ll Time, TScore;
int QPLevel, QPRank, QPExpDecCD; ll QPExp, QPAddExp, TQPScore; bool QPBlighted;
int CurZone; int ZoneProgress, ZoneAttack, ZoneRem;
BoardHistory() {
SX=LX=LY=0;
}
void MarkIn() {
for (Piece &o : Hold) InList.insert(o.GetHash());
for (Piece &o : Next) InList.insert(o.GetHash());
for (Piece &o : Gen.Pool) InList.insert(o.GetHash());
for (Piece &o : Gen.RemPool) InList.insert(o.GetHash());
}
};
string GetBotName(int x) {
if (x<0) return "Default";
return vector<string>({"Nanami T0",
"Silver T2",
"Nanami T2",
"Silver T3",
"Nanami T3",
"Nanami T1",
"Denia T2",
"Denia T3",
"Silver T1",
"Denia T1"})[x];
return vector<string>({"D0",
"S2",
"D2",
"S3",
"D3",
"D1",
"Q2",
"Q3",
"S1",
"Q1"})[x];
}
const double TimeMul = 0.0;
double TimeAcc=0.0; ll LstClock, CurClock, FinalClock;
int GlobalRealTimeDel = 0;
ll GetClock() {
if (!TimeMul) return clock();
CurClock = clock();
TimeAcc += double(CurClock-LstClock)*TimeMul;
ll d = ll(floor(TimeAcc));
FinalClock+=d; TimeAcc-=double(d); LstClock=CurClock;
return FinalClock;
}
bool QPMode = false;
mt19937 GlobalGen; int BeginTime=time(0);
#warning Board
int Obs = -1;
class Board {
int **B, **U, **Age, *FallDest; bool **C;
vector<Monitor> Keys;
Piece Cur, Lst; vector<Piece> Hold, Next;
int PosX, PosY, UID=1, PlaceUID=0;
int BoardID = 0;
PieceGenerator Gen;
int InactiveTime, InactiveTot, FallTime;
int ResetRem, HoldRem;
int LastLock, GravityCD;
int LineClearText, LineClearColor, LineClearAge;
string SpinText; int SpinColor, SpinGrade, SpinAge;
int ComboText, ComboAge, B2BText, B2BAge, B2BBlinkRem, AllClearAge;
int Combo, B2B, Chain; bool SpinSta, RotSta, CurClutch; pair<int,int> LastKick;
bool HalfDown;
int TPiece, TLine, TDig, TAttack, TAC, ActionTime, ActionCD; ll TScore, TQPScore, DScore, DQPScore, Time;
vector<pair<int,pair<ll,ll> > > QPSeg; vector<ll> QPSegTime;
ll QPLevTime; double QPAttackWeightInc;
int QPWeightDec = 0;
int QPLevel=0, QPRank=0, QPExpDecCD=0; ll QPExp=0LL, QPAddExp=0LL;
int LineAfterPC, MasterBegin, QPRevMod2GarbSide;
vector<pair<Action,int> > PendingActions;
vector<Particle> Particles; vector<pair<Particle,int> > DelayParticles;
vector<FloatText> FloatTexts;
vector<Piece*> CustomPiece;
pair<string,int> LastClearType;
vector<GarbageLayer> AttackIn; int HolePos;
//GarbageLayer LatestReceive;
vector<int> AttackOut;
bool ShowParticle;
int DropDelay, LockDelay, GravityDelay, ARE, LCD, CCD, StartDelay=3000, StartMsg, Level;
bool SideGravity = false;
double PDth, PDx, PDy, DNext;
int C2ComboRem, PushCD, HoldPosInc, PreInc;
int GarbCount; double AttackAcc=0.0;
int MutateID=0, AddID=0, ZoneRem=0;
int MutatePos = 0;
bool Over = false;
double BotPos = 0.0;
int LastAttacker=-1, KOMessage=-2;
int StackHeight=0, WindUpCD=0, QPRisePos=0, StockRem=0;
bool QPBlighted = false;
int RoundHeight = 0;
int VanishHeight = 0;
vector<Piece> Pool; EGenerationType GenType;
int LX, LY, SX;
double PX, PY, K;
double tPX, tPY, tK; bool FirstSetScale=true;
int HoldLen=1, NextLen=5, HoldType=1;
int DefaultRot=3, DefaultDir=0;
int DAS=200, ARR=0, SDDAS=200, SDARR=20, HCD=100, DCD=0;
int BaseDropDelay=500, BaseLockDelay=500, BaseGravityDelay=0, BaseARE=0, BaseLCD=0, BaseCCD=200;
int ResetLim = 15;
bool Bot, SpinMode; int BotType=1, ActType=1;
Piece Tg; int TgD, TgX, TgY;
int BotSpeed=1000, SpeedCap=0;
int GarbageGap=8, GarbageDelay=500, GarbageSeg=0, GarbagePass=0, GarbagePush=100, GarbagePreview=10;
bool ForceShowAttack = false;
ELevScaleMode LevScaleMode = LS_Default;
int LevPiece=0, LevLine=0, LevTime=0, LevAttack=0;
int TarPiece=0, TarLine=0, TarDig=0, TarAttack=0; ll TarTime=0, TarScore=0;
bool TypePiece=false, TypeLine=false, TypeDig=false, TypeTime=false, TypeAttack=false, TypeScore=false;
int TargetSta = 0;
int LevPieceInc=0, LevLineInc=0, LevTimeInc=0, LevAttackInc=0;
int LevStart=0, LevBase=0, LevMax=0;
int LevScaleRate = 7;
int MasterThreshold = 0;
int Stock = 0;
bool AutoRespawn = false;
bool HideStat = false;
bool UseZone = false;
int ZoneReq=8, ZoneSeg=4, ZoneTime=5000;
int ZoneProgress=0, ZoneAttack=0;
EBaseRule BaseRule;
EComboRule ComboRule;
ESpinRule SpinRule;
EB2BRule B2BRule;
EAllClearRule AllClearRule;
ERotateSystem RotateSystem;
EGarbageShape GarbageShape;
EGarbageType GarbageType;
EIntRule IntRule;
EGarbageActive GarbageActive;
EGravityType GravityType;
EClutchRule ClutchRule;
int DigBonus = 2;
bool SingleBonus = false;
int OpenerProtect = 14;
int StaticGarbHeight, StartHeight;
int InnerMess=0, SegMess=1000;
int ShadowType = 1;
bool Mutate = false;
bool UseMove=true, UseRotate=true, Use2Rot=true, UseHalf=true,
UseSoftDrop=true, UseHardDrop=true, UseSonicDrop=true,
UseFlip=false, UseUp=false, UseWaste=false, UseLock=false,
UsePlace=false, UseClick=true, UseUndo=false, UseDeep=false;
bool UseTip = false;
deque<BoardHistory> History; int HistoryPos=0;
int SmoothLevel = 3;
bool RandomRot = false;
ETargetType TargetType = TT_Even;
int PaintType = 0;
void ClearSearchProcess() {
if (SearchStep!=-1) {
bool f = false;
for (Status *p : CurLayer) {
if (p==Current) f=true;
delete p;
}
delete Map; delete Tmp;
if (!f) delete Current;
SearchStep = -1;
}
for (Status *o : Recycle) delete o;
Recycle.clear();
}
int NewUID() {
++UID; if (UID>1000000000) UID=1;
return UID;
}
int LatestClock = 0;
void ResetBoard(int Seed=-1) {
Tg=P_Empty; TgX=TgY=StackHeight=ZoneRem=PreInc=0; TgD=-1; Rank=999; Chain=0;
FallTime=LastAttack=TargetSta=0; InCascade=IsZoneClear=CurClutch=GiveQPScoreMsg=false; DNext=0.0;
DropDelay=BaseDropDelay; LockDelay=BaseLockDelay; GravityDelay=BaseGravityDelay;
ARE=BaseARE; LCD=BaseLCD; CCD=BaseCCD; QPSeg.clear(); QPSeg.push_back(make_pair(LevelColor[0],make_pair(0LL,0LL)));
QPSegTime.clear();
KOCount=Badge=ActionCD=ZoneProgress=ZoneAttack=CurZone=0;
LastAttacker=-1; //KOMessage=-2;
//LatestReceive = GarbageLayer(0);
ClearSearchProcess();
if (Seed==-1) Seed=LatestClock;
ClearBoard(); Level=-1;
LastClearType = make_pair("",-1);
Hold.clear(); Next.clear();
int H = max(0,min(100,GetConfig("RandHistory",1)));
int R = max(0,min(100,GetConfig("RandRoll",1)));
int E = max(0,min(100,GetConfig("BagExtra",0)));
MutatePool.clear();
if (ModM==1) {
for (int i=2; i<9; ++i) MutatePool.push_back(i);
}
MutateID=AddID=MutatePos=0;
if (QPMode) Seed+=BoardID-1;
if (Mod2) HoldLen=0;
if (Mod2==2) {
NextLen=min(NextLen,1); GenType=G_Random;
QPRevMod2GarbSide=rand()&1; H=R=ShadowType=0;
}
if (Mod3==2) BaseLCD=max(BaseLCD,1150);
if (Mod5==2) GarbagePreview=max(GarbagePreview,10);
if (Mod6==2) {
StaticGarbHeight=max(StaticGarbHeight,4); GarbageGap=min(GarbageGap,2);
}
if (Mod9) GarbagePush=0;
if (Mutate) {
vector<Piece> MutatePool;
for (Piece p : Pool) MutatePool.push_back(p);
Gen = PieceGenerator(MutatePool,GenType,Seed,H,R,E);
AddID = Pool.size();
}
else Gen=PieceGenerator(Pool,GenType,Seed,H,R,E);
HoldLen=min(HoldLen,10); NextLen=min(NextLen,100);
Lst=Cur=P_Empty; InactiveTime=InactiveTot=FallTime=0; HoldRem=HoldLen;
LineClearText=-1; LineClearAge=5000; LineClearColor=0;
SpinText=""; SpinAge=5000; SpinColor=SpinGrade=0; SpinSta=RotSta=false;
Combo=B2B=B2BText=ComboText=0; ComboAge=B2BAge=5000; B2BBlinkRem=0;
TScore=DScore=TQPScore=DQPScore=0LL; QPLevel=QPRank=QPExpDecCD=0; QPExp=QPAddExp=0LL;
TPiece=TLine=TDig=TAttack=TAC=0; Time=0LL;
ActionTime=int(-BotPos*double(BotSpeed)); AllClearAge=5000; SearchStep=-1;
GarbCount=0; QPBlighted=false; QPLevTime=0LL;
LineAfterPC=LastLock=HoldPosInc=0;
PendingActions.clear();
AttackIn.clear(); AttackOut.clear();
HalfDown = false;
SpinMode = false;
Over = false;
HolePos = rand()%LY+1;
FillNext();
C2ComboRem=PushCD=0;
AttackAcc=QPAttackWeightInc=0.0;
RerollHole(); StockRem=max(0,Stock);
for (int i=0; i<min(LX,max(StaticGarbHeight,StartHeight)); ++i) {
if (randf()*1000.0<SegMess) RerollHole();
AddGarbage(RollGarbage());
}
if (ModS) ChangeSize(LX,4+max(ModP,ModM),6+max(ModP,ModM));
if (Mod3==2) {
for (int i=1; i<=SX-8; ++i) {
for (int j=1; j<=LY; ++j) {
int pi=(i-1)%5, pj=(j-1)%5;
if (max(abs(pi-2),abs(pj-2))==1) B[i][j]=Garb;
}
}
}
if (Mod6==2) {
for (int i=1; i<=SX-8; ++i) {
for (int j=1; j<=LY; ++j) {
if ((i+j)&1) {
B[i][j]=0; continue;
}
if ((j==1)||(j==LY)) B[i][j]=Garb;
else B[i][j]=RollColor();
}
}
}
if (Mod8==2) {
for (int i=1; i<=((SX-1)>>1); ++i) {
int p = rand()%LY+1;
for (int j=1; j<=LY; ++j) {
if (j!=p) B[i][j]=Garb;
else B[i][j]=0;
}
}
}
else if (Mod7==2) {
for (int i=1; i<=min(SX,3); ++i) {
int p = rand()%LY+1;
for (int j=1; j<=LY; ++j) {
if (j!=p) B[i][j]=Garb;
else B[i][j]=0;
}
}
}
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if ((B[i][j])&&(!U[i][j])) U[i][j]=NewUID();
}
}
InactiveTime=InactiveTot=StartDelay;
StartMsg = StartDelay/1000;
Time = -ll(StartDelay);
if (!StartDelay) StartMsg=-1;
for (int i=1; i<=LX; ++i) FallDest[i]=i;
UpdateLevel();
WindUpCD=5000; QPRisePos=0; QPWeightDec=0; ResetRem=ResetLim;
}
void AddParticle(int Delay, int n, int clr, double sz, double dsz, double x, double y, double vx, double vy, double ax, double ay, double th=0.0, double dth=0.0) {
if (!ShowParticle) return;
Particle o = (Particle){x,y,vx,vy,ax,ay,sz,dsz,th,dth,n,clr};
if (Delay) DelayParticles.push_back(make_pair(o,Delay));
else Particles.push_back(o);
}
void AddFloatText(string str, int clr, double sz, double dsz, double bd, double dbd, double x, double y, double vx, double vy, double ax, double ay, double th=0.0, double dth=0.0, double w=1.0, double dw=0.0) {
if (!ShowParticle) return;
FloatTexts.push_back((FloatText){x,y,vx,vy,ax,ay,sz,dsz,bd,dbd,th,dth,w,dw,clr,str});
}
vector<int> MutatePool;
void FillNext(int val=0) {
int lim = max(max(12,val),NextLen+5);
while (Next.size()<lim) {
Piece p = Gen.Roll();
/*#warning Test
if ((!BoardID)&&(p.GetName()=="I")) {
int u = rand()%6+1;
if (u==1) p=P_A;
if (u==2) p=P_B;
if (u==3) p=P_D;
if (u==4) p=P_I;
if (u==5) p=P_I5;
if (u==6) p=P_30;
}*/
if (ModM==1) {
if (MutatePool.empty()) {
for (int i=0; i<9; ++i) MutatePool.push_back(i);
shuffle(MutatePool.begin(), MutatePool.end(), GlobalGen);
}
int u=MutatePool.back(); MutatePool.pop_back();
//u = rand()&1;
if (u<2) {
vector<Piece> lst;
if (p.GetName()=="I") lst=QPModM_I;
else if (p.GetName()=="J") lst=QPModM_J;
else if (p.GetName()=="L") lst=QPModM_L;
else if (p.GetName()=="O") lst=QPModM_O;
else if (p.GetName()=="S") lst=QPModM_S;
else if (p.GetName()=="T") lst=QPModM_T;
else if (p.GetName()=="Z") lst=QPModM_Z;
else {
int r = rand()%7;
if (r==0) lst=QPModM_I;
if (r==1) lst=QPModM_J;
if (r==2) lst=QPModM_L;
if (r==3) lst=QPModM_O;
if (r==4) lst=QPModM_S;
if (r==5) lst=QPModM_T;
if (r==6) lst=QPModM_Z;
}
if (!lst.empty()) {
int pos = max(0,min(Level-1,int(lst.size())-1));
if ((!pos)||(u==1)) p=lst[pos];
else p=lst[rand()%pos];
}
}
}
if (RandomRot) p=GetRotate(p,rand()&3);
Next.push_back(p); Next.back().SetDir(DefaultDir);
}
}
pair<int,int> SpawnPlace(const Piece &_p) {
Piece p=_p; p.SetDir(DefaultDir);
int PLX = p.GetLX();
int LeftMost=-1, RightMost=PLX, UpMost=-1, DownMost=PLX;
for (int i=0; i<PLX; ++i) {
for (int j=0; j<PLX; ++j) {
if (!p.GetGrid(i,j)) continue;
LeftMost = min(LeftMost,j);
RightMost = max(RightMost,j);
UpMost = max(UpMost,i);
DownMost = min(DownMost,i);
}
}
if (UpMost<0) return make_pair(0,0);
int PieceMid=(LeftMost+RightMost)>>1, BoardMid=(LY+1)>>1;
return make_pair(min(LX-(UpMost-DownMost),max(SX-UpMost,SX-DownMost-1)),BoardMid-PieceMid);
}
bool CheckOut(int x, int y) {
return (((x<1)||(y<1))||((x>LX)||(y>LY)));
}
bool CheckGrid(int x, int y) {
if (((x<1)||(y<1))||((x>LX)||(y>LY))) return true;
return ((B[x][y])&&(!C[x][y]));
}
bool CheckPlace(Piece &p, int x, int y) {
int LX = p.GetLX();
for (int i=0; i<LX; ++i) {
for (int j=0; j<LX; ++j) {
if ((p.GetGrid(i,j))&&(CheckGrid(x+i,y+j))) return false;
}
}
return true;
}
bool PlacePiece(Piece &p, int x, int y) {
if (!CheckPlace(p,x,y)) return false;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (C[i][j]) {
B[i][j]=0; C[i][j]=false;
}
}
}
int LX = p.GetLX();
for (int i=0; i<LX; ++i) {
for (int j=0; j<LX; ++j) {
int val = p.GetGrid(i,j);
if (val) {
C[x+i][y+j]=true; B[x+i][y+j]=val;
}
}
}
Cur = p;
PosX=x; PosY=y;
return true;
}
bool CheckSpawn(Piece &_p, int PosInc=0, bool Clutch=false) {
Piece p=_p; p.SetDir(DefaultDir);
pair<int,int> Place = SpawnPlace(p);
if (!Clutch) return CheckPlace(p,Place.first+PosInc,Place.second);
for (int i=0; i<=min(LX,LX-SX+6); ++i) {
if (CheckPlace(p,Place.first+PosInc+i,Place.second)) return true;
}
return false;
}
bool Spawn(Piece &_p, int PosInc=0, int Dir=-1, bool Clutch=false) {
Piece p=_p; p.SetDir((Dir<0)?DefaultDir:Dir);
pair<int,int> Place = SpawnPlace(p);
Place.first += PosInc;
bool f = PlacePiece(p,Place.first,Place.second);
if ((!f)&&(Clutch)) {
for (int i=1; i<=min(LX,LX-SX+6); ++i) {
f = PlacePiece(p,Place.first+i,Place.second);
if ((f)&&(CurClutch)) {
AddNotice("Clutch +"+IToS(i),0xFDD000,0.7,0); break;
}
}
}
if (f) {
Chain = 0;
UpdateLevel(); GravityCD=GravityDelay;
RotSta=false; LastKick=make_pair(0,0); HalfDown=false;
PDth=PDx=PDy=0.0; FallTime=0; ResetRem=ResetLim;
}
return f;
}
bool CheckActive() {
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (C[i][j]) return true;
}
}
return false;
}
bool CheckUp() {
bool f = false;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (!C[i][j]) continue;
if (CheckGrid(i+1,j)) return false;
f = true;
}
}
return f;
}
bool CheckDown() {
bool f = false;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (!C[i][j]) continue;
if (CheckGrid(i-1,j)) return false;
f = true;
}
}
return f;
}
bool CheckLeft() {
bool f = false;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (!C[i][j]) continue;
if (CheckGrid(i,j-1)) return false;
f = true;
}
}
return f;
}
bool CheckRight() {
bool f = false;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (!C[i][j]) continue;
if (CheckGrid(i,j+1)) return false;
f = true;
}
}
return f;
}
bool MoveUp() {
if (!CheckUp()) return false;
bool f = true;
for (int i=LX; i>1; --i) {
for (int j=1; j<=LY; ++j) {
if (C[i-1][j]) {
f = true;
B[i][j]=B[i-1][j]; C[i][j]=true;
B[i-1][j]=0; C[i-1][j]=false;
}
}
}
if (SmoothLevel>=3) --PDx;
++PosX; RotSta=false; return f;
}
bool MoveDown() {
if (!CheckDown()) return false;
bool f = true;
for (int i=1; i<LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (C[i+1][j]) {
f = true;
B[i][j]=B[i+1][j]; C[i][j]=true;
B[i+1][j]=0; C[i+1][j]=false;
}
}
}
--PosX;
RotSta=false; return f;
}
int DeepDrop() {
int p = 0;
for (int d=1; d<=LX; ++d) {
bool f = true;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (!C[i][j]) continue;
if (CheckGrid(i-d,j)) {
f=false; break;
}
}
if (!f) break;
}
if (f) {
p=d; break;
}
}
if (!p) return 0;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (!C[i][j]) continue;
B[i-p][j]=B[i][j]; B[i][j]=0;
C[i-p][j]=true; C[i][j]=false;
}
}
if (!TargetSta) TScore+=ll(p);
PosX-=p; if (SmoothLevel>=3) PDx+=p;
HalfDown=true; RotSta=false;
return p;
}
bool MoveLeft() {
if (!CheckLeft()) return false;
AddMoveParticle(-1);
bool f = true;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<LY; ++j) {
if (C[i][j+1]) {
f = true;
B[i][j]=B[i][j+1]; C[i][j]=true;
B[i][j+1]=0; C[i][j+1]=false;
}
}
}
if (SmoothLevel>=3) ++PDy;
--PosY; RotSta=false; return f;
}
bool MoveRight() {
if (!CheckRight()) return false;
bool f = true;
AddMoveParticle(1);
for (int i=1; i<=LX; ++i) {
for (int j=LY; j>1; --j) {
if (C[i][j-1]) {
f = true;
B[i][j]=B[i][j-1]; C[i][j]=true;
B[i][j-1]=0; C[i][j-1]=false;
}
}
}
if (SmoothLevel>=3) --PDy;
++PosY; RotSta=false; return f;
}
int RotateToX = -10;
bool CheckRotate(int Rot) {
if (!CheckActive()) return false;
int Dir=Cur.GetDir(), Dest=(Dir+Rot)&3;
if (Dir==Dest) return true;
const vector<pair<int,int> > &Kick = GetKickTable(Dir,Dest,Cur.GetRealName(),RotateSystem);
Piece NewP=Cur; NewP.SetDir(Dest);
RotateToX = -10;
for (pair<int,int> o : Kick) {
if (CheckPlace(NewP,PosX+o.second,PosY+o.first)) {
RotateToX=PosX+o.second; return true;
}
}
return false;
}
void AddB2BParticle(int clr, int Lev=1) {
if (!ShowParticle) return;
for (int k=0; k<Lev; ++k) {
for (int i=1; i<=SX; ++i) {
int j = 0;
double sz=0.2+randf()*0.1, th=randf()*2.0*acos(-1.0);
double d=randf(), x=SX-i+0.5+cos(th)*d, y=j-0.5+sin(th)*d;
AddParticle(0, 4, clr, sz*0.5, sz*1.5,
x, y, cos(th), sin(th), 0, 0, randf()*acos(-1.0), 0.3);
j = LY+1;
sz=0.2+randf()*0.1; th=randf()*2.0*acos(-1.0);
d=randf(); x=SX-i+0.5+cos(th)*d; y=j-0.5+sin(th)*d;
AddParticle(0, 4, clr, sz*0.5, sz*1.5,
x, y, cos(th), sin(th), 0, 0, randf()*acos(-1.0), 0.3);
}
for (int j=1; j<=LY; ++j) {
int i = 0;
double sz=0.2+randf()*0.1, th=randf()*2.0*acos(-1.0);
double d=randf(), x=SX-i+0.5+cos(th)*d, y=j-0.5+sin(th)*d;
AddParticle(0, 4, clr, sz*0.5, sz*1.5,
x, y, cos(th), sin(th), 0, 0, randf()*acos(-1.0), 0.3);
i = SX+1;
sz=0.2+randf()*0.1; th=randf()*2.0*acos(-1.0);
d=randf(); x=SX-i+0.5+cos(th)*d; y=j-0.5+sin(th)*d;
AddParticle(0, 4, clr, sz*0.5, sz*1.5,
x, y, cos(th), sin(th), 0, 0, randf()*acos(-1.0), 0.3);
}
}
}
void AddSpinParticle(int Lev) {
if (!ShowParticle) return;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (!C[i][j]) continue;
for (int k=0; k<Lev; ++k) {
double sz=0.2+randf()*0.1, th=randf()*2.0*acos(-1.0);
double d=randf(), x=SX-i+0.5+cos(th)*d, y=j-0.5+sin(th)*d;
AddParticle(0, 4, Mix(0xFFFFFF,Cur.GetColor(),0.3), sz, sz*3.0,
x, y, cos(th), sin(th), 0, 0, randf()*acos(-1.0), 0.3);
}
}
}
}
void AddMoveParticle(int dir) {
if (!ShowParticle) return;
if ((Bot)&&(DropDelay>0)) {
bool f = false;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (C[i][j]) f|=CheckGrid(i+1,j+dir)|CheckGrid(i+1,j);
}
}
if (!f) return;
}
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if ((!C[i][j])||((!CheckGrid(i-1,j))&&(!CheckGrid(i-1,j+dir)))||
((C[i][j-dir])&&((CheckGrid(i-1,j-dir))||(CheckGrid(i-1,j))))) continue;
for (int k=0; k<3; ++k) {
double sz = 0.15;
double th=(randf()-0.5), x=SX-i+1, y=j-1+randf();
AddParticle(0, 3, Mix(0xFFFFFF,Cur.GetColor(),0.5), sz, sz*1.5,
x, y, -sin(th)*8, -double(dir)*cos(th)*8, -sin(th)*4, -double(dir)*cos(th)*4, randf()*acos(-1.0), 0.3);
}
}
}
}
void AddDropParticle() {
if (!ShowParticle) return;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (!C[i][j]) continue;
int cnt = rand()&1;
for (int k=0; k<cnt; ++k) {
double sz=0.1+randf()*0.05, th=randf()*2.0*acos(-1.0);
double d=randf(), x=SX-i+0.5+cos(th)*d, y=j-0.5+sin(th)*d;
AddParticle(0, 3, Mix(0xFFFFFF,Cur.GetColor(),0.3), sz, sz*2,
x, y, -3, 0, 0, 0, randf()*acos(-1.0), 0.3);
}
}
}
}
bool Rotate(int Rot, const Piece Tar=P_Empty) {
if (!CheckActive()) return false;
int Dir=Cur.GetDir(), Dest=(Dir+Rot)&3;
const vector<pair<int,int> > &Kick = GetKickTable(Dir,Dest,Cur.GetRealName(),RotateSystem);
Piece NewP = Cur;
if (Tar.GetHash()!=P_Empty.GetHash()) NewP=Tar;
NewP.SetDir(Dest);
for (pair<int,int> o : Kick) {
if (CheckPlace(NewP,PosX+o.second,PosY+o.first)) {
int del = o.second-GetShift(Dest,Cur.GetRealName(),RotateSystem).second
+GetShift(Dir,Cur.GetRealName(),RotateSystem).second;
if ((!Bot)&&(del>0)) {
if (ResetRem) {
if (ResetLim<Max) --ResetRem;
}
else return false;
}
PlacePiece(NewP, PosX+o.second, PosY+o.first);
if (!RotSta) HalfDown=false;
RotSta=true; LastKick=make_pair(o.second,o.first);
if (((o.second<0)||((!o.second)&&(o.first)&&(!Dir)))&&(Rot==2)&&((Dir!=2)||(IsOType(Cur.GetRealName()))||(IsStrictHalfSame(Cur.GetRealName())))) HalfDown=true;
else if ((Rot!=2)&&(!IsOType(Cur.GetRealName()))) HalfDown=false;
int Lev = GetSpinLevel(Cur);
if (Lev) AddSpinParticle(Lev);
if (SmoothLevel>=2) {
PDx-=o.second; PDy-=o.first;
if (((Dir+1)&3)==Dest) PDth+=acos(-1.0)*0.5;
if (((Dir+3)&3)==Dest) PDth-=acos(-1.0)*0.5;
if (((Dir+2)&3)==Dest) {
if (DefaultRot==1) PDth+=acos(-1.0);
else PDth-=acos(-1.0);
}
}
return true;
}
}
return false;
}
inline bool IsSpinBonus(const string &Name) {
return (Name=="T");
}
vector<pair<int,int> > CPos;
bool GarbFuse = false;
void Lock() {
GarbFuse=false; TgD=-1; TgX=0;
int d = Cur.GetDir();
Lst=Cur; LastLock=0;
CPos.clear();
SpinSta = ((!CheckUp())&&(!CheckDown())&&(!CheckLeft())&&(!CheckRight()));
vector<int> BombLines;
int cU = NewUID();
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (C[i][j]) {
CPos.push_back(make_pair(i,j));
C[i][j]=false; Age[i][j]=500; U[i][j]=cU;
int p = i-1;
while ((p>0)&&((B[p][j]==GarbLock)||(B[p][j]==GarbBomb))) {
if (B[p][j]==GarbLock) {
B[p][j] = Garb;
for (int k=0; k<2; ++k) {
double sz=0.2+randf()*0.1, th=randf()*2.0*acos(-1.0);
double d=randf(), x=SX-p+0.5+cos(th)*d, y=j-0.5+sin(th)*d;
AddParticle(0, 4, abs(GarbLock), sz, sz*3.0,
x, y, cos(th), sin(th), 0, 0, randf()*acos(-1.0), 0.3);
}
}
else BombLines.push_back(p);
--p; GarbFuse=true;
}
}
}
}
sort(BombLines.begin(),BombLines.end()); int pre=-1;
for (int i : BombLines) {
if (pre==i) continue;
pre = i;
for (int j=1; j<=LY; ++j) {
if (B[i][j]!=Garb) {
B[i][j] = Garb;
for (int k=0; k<2; ++k) {
double sz=0.2+randf()*0.1, th=randf()*2.0*acos(-1.0);
double d=randf(), x=SX-i+0.5+cos(th)*d, y=j-0.5+sin(th)*d;
AddParticle(0, 4, abs(GarbBomb), sz, sz*3.0,
x, y, cos(th), sin(th), 0, 0, randf()*acos(-1.0), 0.3);
}
}
}
}
return;
}
void Waste() {
SpinSta = false;
CPos.clear();
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (C[i][j]) {
C[i][j]=false; B[i][j]=0;
}
}
}
Cur = P_Empty;
return;
}
void HardDrop() {
while (CheckDown()) {
AddDropParticle(); MoveDown(); if (!TargetSta) TScore+=2LL;
}
Lock();
}
int SonicDrop(bool HaveScore=false) {
int res = 0;
while (CheckDown()) {
if ((!Bot)&&(HaveScore)) AddDropParticle();
MoveDown(); ++res; if ((HaveScore)&&(!TargetSta)) ++TScore;
}
return res;
}
void ClearBoard(bool Eff=false) {
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
//if (!C[i][j]) continue;
if ((B[i][j])&&(!C[i][j])&&(Eff)) {
double th = (randf()*2.0-1.0)*acos(-1.0)*0.1;
double v = 15.0;
int clr = Mix(0xFFFFFF,abs(B[i][j]),0.2);
AddParticle(0, 8, clr, 0.15, 0,
SX-i+0.5, j-0.5, -v*cos(th), v*sin(th), 60, 0,
randf()*2.0*acos(-1.0), 0.1);
}
B[i][j]=Age[i][j]=U[i][j]=0; C[i][j]=false;
}
}
}
bool IsUnclearable(int x) {
return ((x==Solid)||(x==GarbZone)||(x==GarbRound)||(x==GarbLock)||(x==GarbBomb)||((x>=GarbQuest)&&(x<=GarbQuest+20)));
}
int DigVal, CurZone=0;
int ZonePreClearLines() {
int Lines = 0;
for (int i=1; i<=LX; ++i) {
bool f=true, g=false;
for (int j=1; j<=LY; ++j) {
if (!B[i][j]) f=false;
if (IsUnclearable(B[i][j])) f=false;
if (B[i][j]<0) g=true;
}
if (f) ++Lines;
}
int FullPos=0, EmptyPos=Lines;
for (int i=1; i<=LX; ++i) {
bool f=true, g=false;
for (int j=1; j<=LY; ++j) {
if (!B[i][j]) f=false;
if (IsUnclearable(B[i][j])) f=false;
if (B[i][j]<0) g=true;
}
if (f) FallDest[i]=++FullPos;
else FallDest[i]=++EmptyPos;
}
return Lines;
}
int PreClearLines() {
if (CurZone) return ZonePreClearLines();
int res=0, p=0;
int Dig = 0;
vector<int> Place;
for (int i=1; i<=LX; ++i) {
bool f=true, g=false;
for (int j=1; j<=LY; ++j) {
if (!B[i][j]) f=false;
if (IsUnclearable(B[i][j])) f=false;
if (B[i][j]<0) g=true;
}
if ((f)&&(i>RoundHeight)) {
++res; if (g) ++Dig;
Place.push_back(i);
FallDest[i] = 0;
if (GravityType!=GV_Default) ++p;
}
else {
if (f) ++res;
FallDest[i] = ++p;
}
}
for (int i : Place) {
for (int j=1; j<=LY; ++j) {
double th = (randf()*2.0-1.0)*acos(-1.0)*0.1;
double v = 15.0;
int clr = Mix(0xFFFFFF,abs(B[i][j]),0.2);
AddParticle(LCD*j/LY, 8, clr, 0.15, 0,
SX-i+0.5, j-0.5, -v*cos(th), v*sin(th), 60, 0,
randf()*2.0*acos(-1.0), 0.1);
}
}
if (!TargetSta) TDig+=Dig;
DigVal = Dig;
return res;
}
int ZoneClearLines() {
int res = 0;
ReallocateUID();
int cU = NewUID();
for (int i=1; i<=LX; ++i) {
bool f = true;
for (int j=1; j<=LY; ++j) {
if (!B[i][j]) f=false;
else U[i][j]+=res*1000000;
if (IsUnclearable(B[i][j])) f=false;
}
if (f) {
++res;
for (int j=1; j<=LY; ++j) {
B[i][j]=GarbZone; Age[i][j]=500; U[i][j]=cU;
}
if (i==res) continue;
for (int j=1; j<=LY; ++j) {
B[0][j]=B[i][j]; Age[0][j]=Age[i][j]; U[0][j]=U[i][j];
}
for (int ii=i; ii>res; --ii) {
for (int j=1; j<=LY; ++j) {
B[ii][j]=B[ii-1][j]; Age[ii][j]=Age[ii-1][j]; U[ii][j]=U[ii-1][j];
}
}
for (int j=1; j<=LY; ++j) {
B[res][j]=B[0][j]; Age[res][j]=Age[0][j]; U[res][j]=U[0][j];
B[0][j]=Age[0][j]=U[0][j]=0;
}
}
}
ReallocateUID();
return res;
}
void UDfs(int x, int y, int u, int nw) {
if (((x<1)||(y<1))||((x>LX)||(y>LY))) return;
if ((!B[x][y])||(C[x][y])||(U[x][y]!=u)) return;
U[x][y] = nw;
UDfs(x-1,y,u,nw); UDfs(x+1,y,u,nw);
UDfs(x,y-1,u,nw); UDfs(x,y+1,u,nw);
}
void ReallocateUID(int beg=0) {
const int D = 1000000000;
PlaceUID = 0;
for (int i=beg+1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (U[i][j]) U[i][j]+=D;
}
}
if (!beg) UID=1;
for (int i=beg+1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (U[i][j]<D) continue;
UDfs(i, j, U[i][j], NewUID());
}
}
}
int ClearLines() {
if (CurZone) return ZoneClearLines();
ReallocateUID();
int res=0, p=0;
for (int i=1; i<=LX; ++i) {
bool f = true;
for (int j=1; j<=LY; ++j) {
if (!B[i][j]) f=false;
else U[i][j]+=res*1000000;
if (IsUnclearable(B[i][j])) f=false;
}
if ((f)&&(i>RoundHeight)) {
++res;
if (GravityType!=GV_Default) {
++p;
for (int j=1; j<=LY; ++j) B[p][j]=Age[p][j]=U[p][j]=0;
}
}
else {
++p;
if (p!=i) {
for (int j=1; j<=LY; ++j) {
B[p][j]=B[i][j]; B[i][j]=0;
Age[p][j]=Age[i][j]; U[p][j]=U[i][j];
Age[i][j]=U[i][j]=0;
}
}
if (f) {
++res;
for (int j=1; j<=LY; ++j) B[i][j]=GarbRound;
}
}
}
for (int i=p+1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) B[i][j]=Age[i][j]=U[i][j]=0;
}
ReallocateUID();
return res;
}
bool CheckAllClear() {
for (int i=1; i<=LX; ++i) {
bool f=true, g=false;
for (int j=1; j<=LY; ++j) {
if (B[i][j]) g=true;
else f=false;
}
if ((g)&&(!f)) return false;
}
return true;
}
void AttackSeq(int x) {
if (x<1) return;
AttackOut.push_back(x);
}
int Adj4C(int x, int y) {
int r = 0;
for (int ii=-1; ii<=1; ++ii) {
for (int jj=-1; jj<=1; ++jj) {
if (abs(ii)+abs(jj)!=1) continue;
if (C[x+ii][y+jj]) ++r;
}
}
return r;
}
int Adj4PC(int x, int y) {
int r = 0;
for (int ii=-1; ii<=1; ii+=2) {
for (int jj=-1; jj<=1; jj+=2) {
if (C[x+ii][y+jj]) ++r;
}
}
return r;
}
int Adj8C(int x, int y) {
int r = 0;
for (int ii=-1; ii<=1; ++ii) {
for (int jj=-1; jj<=1; ++jj) {
if ((!ii)&&(!jj)) continue;
if (C[x+ii][y+jj]) ++r;
}
}
return r;
}
int Adj4B(int x, int y) {
int r = 0;
for (int ii=-1; ii<=1; ++ii) {
for (int jj=-1; jj<=1; ++jj) {
if (abs(ii)+abs(jj)!=1) continue;
if ((CheckGrid(x+ii,y+jj))||(C[x+ii][y+jj])) ++r;
}
}
return r;
}
int Adj4PB(int x, int y) {
int r = 0;
for (int ii=-1; ii<=1; ii+=2) {
for (int jj=-1; jj<=1; jj+=2) {
if ((CheckGrid(x+ii,y+jj))||(C[x+ii][y+jj])) ++r;
}
}
return r;
}
int Adj8B(int x, int y) {
int r = 0;
for (int ii=-1; ii<=1; ++ii) {
for (int jj=-1; jj<=1; ++jj) {
if ((!ii)&&(!jj)) continue;
if ((CheckGrid(x+ii,y+jj))||(C[x+ii][y+jj])) ++r;
}
}
return r;
}
int DefaultSpinLevel(Piece p) {
if (SpinSta) {
if (IsOType(p.GetName())) {
int tot = 0;
for (int i=1; i<LX; ++i) {
for (int j=1; j<=LY; ++j) {
if ((C[i][j])&&(B[i+1][j])&&(!C[i+1][j])) ++tot;
}
}
return (tot>=2)?3:2;
}
if (HalfDown) return 2;
bool ex=false, sw=false, ew=false;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if ((C[i][j])&&(Adj4B(i,j)<=1)) return 2;
if ((C[i][j])&&(Adj4B(i,j)<=2)) ex=true;
if ((!B[i][j])&&(Adj4C(i,j)>=2)) sw=true;
if ((!C[i][j])&&(Adj4C(i,j)>=2)) ew=true;
}
}
if ((ex)&&((sw)||(!ew))) return 2;
return 3;
}
if (RotSta) {
int tot=0, cnt=0;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if ((C[i][j])&&(Adj4C(i,j)>=2)&&(Adj8C(i,j)>=3)) {
int v = Adj8B(i,j);
if (v<6) return 0;
++tot;
if (Adj8B(i,j)>=7) ++cnt;
}
}
}
if ((cnt)&&(cnt>=tot-1)) return 1;
else if ((IsSpinBonus(p.GetName()))&&(CornerCheck()>=3)) return 1;
}
return 0;
}
int CornerCheck() {
int res=0, mx=0;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (!C[i][j]) continue;
mx = max(mx,Adj8C(i,j));
}
}
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (!C[i][j]) continue;
if (Adj8C(i,j)!=mx) continue;
res = max(res,Adj4PB(i,j));
}
}
return res;
}
int GetSpinLevelP(Piece p) {
if (p.GetHash()==P_Empty.GetHash()) return 0;
SpinSta = ((!CheckUp())&&(!CheckDown())&&(!CheckLeft())&&(!CheckRight()));
if (CheckDown()) return 0;
if ((SpinSta)&&(Mod8)) return 3;
if ((!RotSta)&&(!SpinSta)) return 0;
if (SpinRule==SR_Easy) return 3;
string Name = p.GetRealName();
if (SpinRule==SR_None) return 0;
if (SpinRule==SR_Default) {
int r = DefaultSpinLevel(p);
if (!IsSpinBonus(p.GetName())) {
if (r==1) r=0;
}
return r;
}
if (SpinRule==SR_AllSpin) {
int r = DefaultSpinLevel(p);
if (r>1) r=3;
return r;
}
if (SpinRule==SR_AllSemi) {
int r = DefaultSpinLevel(p);
if (!IsSpinBonus(p.GetName())) {
if (r>1) r=2;
else r=0;
}
return r;
}
if (SpinRule==SR_AllMini) {
int r = DefaultSpinLevel(p);
if (!IsSpinBonus(p.GetName())) {
if (r>1) r=1;
else r=0;
}
return r;
}
if (SpinRule==SR_IO) {
int r = DefaultSpinLevel(p);
if (!IsSpinBonus(p.GetName())) {
if (r>1) r=1;
else r=0;
}
else if (r==2) r=1;
return r;
}
if (SpinRule==SR_Guildline) {
if (!RotSta) return 0;
if (!IsSpinBonus(p.GetName())) return 0;
bool f = true;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if ((C[i][j])&&(Adj4C(i,j)>2)) {
int d = Adj4PB(i,j);
if (d<3) return 0;
}
if ((!B[i][j])&&(Adj4C(i,j)>1)) f=false;
}
}
return ((f)||((abs(LastKick.first)>=2)&&(abs(LastKick.second)>=1)))?3:1;
}
return 0;
}
int GetSpinLevel(Piece p) {
int r = GetSpinLevelP(p);
if (Mod2==2) r=min(r,1);
return r;
}
void AddAttackText(int Attack, int clro, int clri, double cpx, double cpy, bool Spin, double bd=1.0) {
if ((!ShowAttack)&&(!ForceShowAttack)) return;
double sz = sqrt(double(min(Attack,15)+1));
double x=SX-cpx+1-(randf()-0.8)*6.0, y=-sz;
double v=sz*0.6, th=randf()*0.5;
if (TPiece&1) y=LY+sz;
double rot = (randf()-0.5)*0.2;
double rr = (Spin)?((y<0)?-0.05:0.05):0;
double vx=v*sin(th), vy=v*cos(th)*((y<0)?-1:1);
AddFloatText(IToS(Attack), clro, sz, 0, 0.3*bd, 0.075,
x, y, vx, vy, -vx*0.25, -vy*0.25, rot, rr);
AddFloatText(IToS(Attack), clri, sz, 0, 0.2*bd, 0.05,
x, y, vx, vy, -vx*0.25, -vy*0.25, rot, rr);
}
int BaseScore(int Lines, int SpinLev) {
vector<int> List = {0,100,300,500,800,1600,3000};
if (SpinLev==1) List={100,200,600,1000,1800,3200};
if (SpinLev==2) List={200,400,1000,1600,2600,4000};
if (SpinLev==3) List={400,800,1200,1600,2600,4000};
if (Lines<0) return 0;
if (Lines>=List.size()) return List.back()+1000*(Lines-List.size()+1);
return List[Lines];
}
int GetBaseAttack(int Lines) {
if (!Lines) return 0;
if (BaseRule==BSR_Default) return Lines-(Lines<4);
if (BaseRule==BSR_Equal) return Lines;
if (BaseRule==BSR_Classic) return (Lines<3)?0:Lines-1;
if (BaseRule==BSR_ASC) return max(0,Lines-1);
if (BaseRule==BSR_Arcade) return (Lines<2)?0:Lines;
return 0;
}
double GetComboAttack(int Combo) {
if (ComboRule==CR_Default) {
if (Combo<2) return 0;
return log(1.0+1.25*Combo);
}
vector<int> lst;
if (ComboRule==CR_Guildline) lst={2,4,6,8,11};
if (ComboRule==CR_Friends) lst={2,5,5,7,12};
if (ComboRule==CR_Expert) lst={2,5,7,9,12};
if (ComboRule==CR_Battle) lst={1,3,5,7};
if (ComboRule==CR_99) lst={1,3,5,7,10};
if (ComboRule==CR_PPT) lst={2,4,6,8,13};
if (ComboRule==CR_Effect) lst={2,4,7,13};
if (ComboRule==CR_Zone) lst={2,4,12};
if (ComboRule==CR_C2) lst={1,4,6,7,7,8,8,9,9,10};
if (ComboRule==CR_Techmino) lst={3};
if (ComboRule==CR_Classic) lst={1};
double res = 0.0;
for (int x : lst) {
if (Combo>=x) ++res;
}
return res;
}
double GetB2BAttack(int B2B) {
if (B2B<1) return 0;
if (B2BRule==BR_Chain) {
if (B2B==1) return 1;
double p = 1.0+log(0.8*B2B+1);
return floor(p)+(1.0+p-floor(p))/3.0;
}
return 1;
}
double GetMultiplerComboAttack(int Combo, double Attack, int Lines) {
if (ComboRule==CR_Default) Attack*=(1.0+max(0,Combo)*0.25);
if (ComboRule==CR_Techmino) {
Combo = min(12,Combo);
if (Lines>1) Attack*=(1.0+max(0,Combo)*0.25);
else Attack*=(1.0+max(0,Combo)*0.15);
if (Combo>=3) ++Attack;
}
return Attack;
}
void ChangeSize(int _LX, int _LY, int _SX, int FillStart=1) {
ClearSearchProcess();
vector<vector<pair<int,int> > > o(LX+2,vector<pair<int,int> >(LY+2));
int OLX=LX, OLY=LY;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if ((B[i][j])&&(!C[i][j])) o[i][j]=make_pair(B[i][j],U[i][j]);
}
}
for (int i=0; i<=LX+1; ++i) {
delete[] B[i]; delete[] C[i]; delete[] Age[i]; delete[] U[i];
}
delete[] B; delete[] C;
delete[] Age; delete[] FallDest; delete[] U;
LX=_LX; LY=_LY; SX=_SX;
B = new int*[LX+2];
C = new bool*[LX+2];
Age = new int*[LX+2];
U = new int*[LX+2];
FallDest = new int[LX+2];
for (int i=0; i<=LX+1; ++i) {
FallDest[i] = 0;
B[i] = new int[LY+2];
C[i] = new bool[LY+2];
Age[i] = new int[LY+2];
U[i] = new int[LY+2];
for (int j=0; j<=LY+1; ++j) {
Age[i][j]=B[i][j]=U[i][j]=0; C[i][j]=false;
}
}
for (int i=1; i<=min(LX,OLX); ++i) {
int Fill = 0;
for (int j=1; j<=OLY; ++j) {
if (o[i][j].first==Solid) {
Fill=Solid; break;
}
if (o[i][j].first==Garb) Fill=Garb;
}
if (Fill) {
for (int j=1; j<=LY; ++j) {
B[i][j]=Fill; U[i][j]=NewUID();
}
}
for (int j=1; j<=OLY; ++j) {
int nj=FillStart+j-1; if ((nj<1)||(nj>LY)) continue;
if (o[i][j].first) {
B[i][nj]=o[i][j].first; U[i][nj]=o[i][j].second;
Age[i][nj] = 500;
}
else B[i][nj]=U[i][nj]=0;
}
}
for (GarbageLayer &o : AttackIn) {
vector<int> New(LY+2);
bool f = false;
for (int x : o.B) {
if (x==Solid) f=true;
}
for (int j=1; j<=LY; ++j) New[j]=(f)?Solid:Garb;
for (int j=1; j<=OLY; ++j) {
int nj=FillStart+j-1; if ((nj<1)||(nj>LY)) continue;
New[nj] = o.B[j];
}
o.B = New;
}
}
bool ReadHistoryMsg = false;
#define WriteIn(x) o.x=x
BoardHistory WriteHistory() {
BoardHistory o;
WriteIn(SX); WriteIn(LX); WriteIn(LY);
o.B = vector<vector<int> >(LX+2,vector<int>(LY+2));
o.U = vector<vector<int> >(LX+2,vector<int>(LY+2));
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
o.B[i][j]=B[i][j]; o.U[i][j]=U[i][j]; if (C[i][j]) o.B[i][j]=o.U[i][j]=0;
}
}
WriteIn(Gen); WriteIn(Hold); WriteIn(Next); WriteIn(TargetSta);
WriteIn(AttackIn); WriteIn(TPiece);
WriteIn(TLine); WriteIn(TDig); WriteIn(TAttack);
WriteIn(TAC); WriteIn(Combo); WriteIn(B2B); WriteIn(CurClutch);
WriteIn(TScore); WriteIn(Time); WriteIn(C2ComboRem);
WriteIn(TQPScore); WriteIn(QPExp); WriteIn(QPAddExp);
WriteIn(QPLevel); WriteIn(QPRank); WriteIn(QPExpDecCD); WriteIn(QPBlighted);
WriteIn(CurZone); WriteIn(ZoneProgress); WriteIn(ZoneAttack); WriteIn(ZoneRem);
return o;
}
#undef WriteIn
#define WriteIn(x) x=o.x;
void ReadHistory(BoardHistory o) {
if (!o.LX) return;
if ((o.SX!=SX)||(o.LX!=LX)||(o.LY!=LY)) ChangeSize(o.LX,o.LY,o.SX);
for (int i=1; i<=LX; ++i) {
FallDest[i] = i;
for (int j=1; j<=LY; ++j) {
B[i][j]=o.B[i][j]; C[i][j]=false; Age[i][j]=U[i][j]=0;
if (B[i][j]) U[i][j]=o.U[i][j];
}
}
WriteIn(Gen); WriteIn(Hold); WriteIn(Next); WriteIn(TargetSta);
WriteIn(AttackIn); WriteIn(TPiece);
WriteIn(TLine); WriteIn(TDig); WriteIn(TAttack);
WriteIn(TAC); WriteIn(Combo); WriteIn(B2B); WriteIn(CurClutch);
WriteIn(TScore); WriteIn(Time); WriteIn(C2ComboRem);
WriteIn(TQPScore); WriteIn(QPExp); WriteIn(QPAddExp);
WriteIn(QPLevel); WriteIn(QPRank); WriteIn(QPExpDecCD); WriteIn(QPBlighted);
WriteIn(CurZone); WriteIn(ZoneProgress); WriteIn(ZoneAttack); WriteIn(ZoneRem);
if ((Combo>1)||((Combo)&&(ComboRule==CR_C2))) {
ComboAge=0; ComboText=(ComboRule==CR_C2)?Combo:Combo-1;
}
else {
ComboAge=5000; ComboText=0;
}
if ((B2B>1)||((B2B)&&(B2BRule==BR_Techmino))) {
B2BAge=0; B2BText=(B2BRule==BR_Techmino)?B2B:B2B-1;
}
else {
B2BAge=5000; B2BText=0;
}
Cur = P_Empty;
InactiveTime=InactiveTot=FallTime=0; Over=false;
ReadHistoryMsg = true;
TgD=-1; ClearSearchProcess();
}
#undef WriteIn
#warning Board::AREProcess
int LastAttack = 0;
void AddNotice(string str, int clr, double sz=1.0, double xp=0.25) {
AddFloatText(str, clr, sz, 0, 0.15, 0.05, SX*xp, LY*0.5, 0, 0, 0, 0, 0, 0, 1.5, 0.5);
}
void ClearVanish() {
if (VanishHeight<1) return;
for (int i=VanishHeight; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (!B[i][j]) continue;
double th = (randf()*2.0-1.0)*acos(-1.0)*0.1;
double v = 15.0;
int clr = Mix(0xFFFFFF,abs(B[i][j]),0.2);
AddParticle(LCD*j/LY, 8, clr, 0.15, 0,
SX-i+0.5, j-0.5, -v*cos(th), v*sin(th), 60, 0,
randf()*2.0*acos(-1.0), 0.1);
B[i][j]=Age[i][j]=U[i][j]=0; C[i][j]=false;
}
}
}
bool InCascade = false;
static int V[110][110], SegTreeM[20010], SegTreeP[20010], Dis[10010];
static vector<pair<int,int> > Graph[10010]; static bool Vis[10010];
void CDfs(int x, int y, int u, int b, int val) {
if (((x<1)||(y<1))||((x>LX)||(y>LY))) return;
if ((!B[x][y])||(V[x][y])) return;
if (((GravityType==GV_Cascade)||(GravityType==GV_Separate)||(GravityType==GV_Avalanche))&&(U[x][y]!=u)) return;
if ((GravityType==GV_Color)&&(B[x][y]!=b)) return;
V[x][y] = val;
CDfs(x-1,y,u,b,val); CDfs(x+1,y,u,b,val);
CDfs(x,y-1,u,b,val); CDfs(x,y+1,u,b,val);
}
void SegTreeUpdate(int x, int val, int id) {
int u = x+id-1;
SegTreeM[u]=val; SegTreeP[u]=x; u>>=1;
while (u) {
if (SegTreeM[u<<1]<=SegTreeM[u<<1|1]) {
SegTreeM[u]=SegTreeM[u<<1]; SegTreeP[u]=SegTreeP[u<<1];
}
else {
SegTreeM[u]=SegTreeM[u<<1|1]; SegTreeP[u]=SegTreeP[u<<1|1];
}
u >>= 1;
}
}
bool CheckCascade() {
if ((GravityType==GV_None)||(GravityType==GV_Default)) return false;
for (int i=0; i<=LX+1; ++i) {
for (int j=0; j<=LY+1; ++j) V[i][j]=0;
}
int id = 0;
if (GravityType==GV_Fall) {
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (B[i][j]) V[i][j]=++id;
}
}
}
else {
if ((GravityType==GV_Separate)||(GravityType==GV_Avalanche)) {
bool f = false;
for (int i=1; i<=LX; ++i) {
bool ff = true;
for (int j=1; j<=LY; ++j) {
if (B[i][j]) {
ff = false;
if (f) U[i][j]=NewUID();
}
}
if (ff) f=true;
}
}
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if ((B[i][j])&&(!V[i][j])) CDfs(i,j,U[i][j],B[i][j],++id);
}
}
}
++id;
for (int i=1; i<=id; ++i) {
Graph[i].clear(); Dis[i]=LX; Vis[i]=false;
}
for (int i=1; i<=(id<<1); ++i) {
SegTreeM[i]=LX; SegTreeP[i]=0;
}
for (int j=1; j<=LY; ++j) {
int pre=id, del=0;
for (int i=1; i<=LX; ++i) {
++del; if (!V[i][j]) continue;
if (IsUnclearable(B[i][j])) Graph[id].push_back(make_pair(V[i][j],0));
if (V[i][j]!=pre) Graph[pre].push_back(make_pair(V[i][j],del-1));
pre=V[i][j]; del=0;
}
}
if ((GravityType!=GV_Separate)&&(GravityType!=GV_Fall)&&(GravityType!=GV_Avalanche)) {
for (int i=1; i<=LX; ++i) {
int lst = -1;
for (int j=1; j<=LY; ++j) {
if (B[i][j]<0) {
if ((lst!=-1)&&(V[i][j]!=lst)) {
Graph[lst].push_back(make_pair(V[i][j],0));
Graph[V[i][j]].push_back(make_pair(lst,0));
}
lst = V[i][j];
}
}
}
}
Dis[id]=0; SegTreeUpdate(id,0,id);
while (SegTreeM[1]<LX) {
int u=SegTreeP[1]; Vis[u]=true; SegTreeUpdate(u,LX,id);
for (pair<int,int> o : Graph[u]) {
int v=o.first, w=Dis[u]+o.second;
if ((!Vis[v])&&(w<Dis[v])) {
Dis[v]=w; SegTreeUpdate(v,Dis[v],id);
}
}
}
bool flag = false;
for (int i=1; i<=id; ++i) {
if ((Dis[i])&&(Dis[i]<LX)) {
flag=true; break;
}
}
if (!flag) return false;
ReallocateUID();
int pos = LX+1;
for (int i=1; i<=LX; ++i) {
FallDest[i] = i;
for (int j=1; j<=LY; ++j) {
if ((V[i][j])&&(Dis[V[i][j]])) {
Age[i][j]=-Dis[V[i][j]]; U[i][j]+=1000000*Dis[V[i][j]];
pos = min(pos,i+Age[i][j]);
}
}
}
if (GravityType==GV_Avalanche) {
for (int i=max(pos,1); i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (B[i][j]) U[i][j]=NewUID();
}
}
}
ReallocateUID();
return true;
}
void CascadeProcess() {
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if ((!B[i][j])||(Age[i][j]>=0)) continue;
int d=i+Age[i][j]; if (d<1) continue;
B[d][j]=B[i][j]; Age[d][j]=500; U[d][j]=U[i][j];
B[i][j]=Age[i][j]=U[i][j]=0;
}
}
}
void PreAREProcess(bool IsPlace=true, bool IsCascade=false) {
ClearVanish();
//if (IsPlace) CurZone=EnableZone;
int PreTLine = TLine;
Piece p = Cur;
Cur = P_Empty;
int RealLines=PreClearLines(), Lines=RealLines;
CurClutch = false;
if ((ClutchRule==CLR_Default)&&(RealLines)) CurClutch=true;
if (ClutchRule==CLR_Always) CurClutch=true;
if (RealLines) ++Chain;
bool AllClear = ((RealLines)&&(CheckAllClear()));
if (AllClear) AllClearAge=0;
if ((!ReadHistoryMsg)&&(IsPlace)) {
if (!TargetSta) ++TPiece;
}
if ((!TargetSta)&&(!CurZone)) TLine+=RealLines;
InactiveTot = (Lines)?LCD:ARE;
if (SpeedCap) InactiveTot=max(InactiveTot,int(min(100000000LL,max(0LL,ll(TPiece)*ll(SpeedCap)-Time))));
InactiveTime = InactiveTot;
PreInc = HoldPosInc+BeginInc;
HoldPosInc = 0;
double cpx=0, cpy=0; int cpt=0;
for (pair<int,int> o : CPos) {
++cpt; cpx+=o.first; cpy+=o.second;
if (((o.first>0)&&(o.second>0))&&((o.first<=LX)&&(o.second<=LY))) C[o.first][o.second]=true;
}
if (cpt) {
cpx/=double(cpt); cpy/=double(cpt);
}
int SpinLev = GetSpinLevel(p);
if ((Mod8)&&(!SpinSta)) SpinLev=min((Bot)?0:1,SpinLev);
for (pair<int,int> o : CPos) {
if (((o.first>0)&&(o.second>0))&&((o.first<=LX)&&(o.second<=LY))) C[o.first][o.second]=false;
}
if ((Mod8)&&(SpinSta)) SpinLev=3;
if ((Mod8==2)&&(!SpinLev)) Lines=0;
if (SpinLev) {
SpinText = Lst.GetRealName();
SpinAge=0; SpinColor=Lst.GetColor(); SpinGrade=SpinLev;
if (Mod8==2) {
SpinColor=0x9999FF; SpinText="X";
}
}
if ((Chain>1)&&(RealLines)) {
SpinText=IToS(Chain)+" Chain"; SpinColor=0xCCCC00; SpinGrade=SpinAge=0;
}
if ((SpinLev)||(RealLines)) {
pair<string,int> NewClearType = make_pair((((Mod8)&&(Bot))?SpinSta:SpinLev)?p.GetRealName():"",Lines);
if (Mod8==2) {
if (SpinLev) NewClearType.first="X";
else NewClearType.second=0;
}
if (!RealLines) NewClearType.second=-1;
if ((Mod8)&&(NewClearType==LastClearType)&&(Chain<2)) {
for (int k=1; k<=((Mod8==2)?SX:1); ++k) {
GarbageLayer o(LY);
for (int i=1; i<=LY; ++i) o.B[i]=Garb;
int tp = GarbQuest+max(1,min(20,Level+5));
o.B[rand()%LY+1] = tp;
if ((Mod6)&&(rand()&1)) o.B[rand()%LY+1]=tp;
AddGarbage(o, 1);
}
}
else if (Mod8) {
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (C[i][j]) continue;
if ((B[i][j]>=GarbQuest)&&(B[i][j]<=GarbQuest+20)) {
--B[i][j]; if (B[i][j]<=GarbQuest) B[i][j]=Age[i][j]=U[i][j]=0;
}
}
}
}
LastClearType = NewClearType;
}
if ((Lines)&&(!SpinLev)&&(Lines<4)) {
if (((BotType==1)||(BotType==3))&&(SpinRule==SR_Guildline)&&(!Mod8)) SpinMode=false;
}
double CalcAttack=0.0, BaseAttack=0.0; int Surge=0;
if (RealLines) {
int val = Lines;
if ((Mod6==2)&&(!QPBlighted)&&(!DigVal)) val=0;
LineClearText = min(int(LineClearWord.size()-1),max(0,val));
LineClearAge=0; LineClearColor=0xFFFFFF;
if (Mod8<2) BaseAttack=GetBaseAttack(Lines);
if (SpinLev) {
if (SpinLev==3) BaseAttack=Lines*2;
else if (SpinLev==2) ++BaseAttack;
}
}
int ComboSta = (RealLines)?1:-1;
if ((ComboRule==CR_Arcade)&&(RealLines<2)) ComboSta=min(ComboSta,0);
if (ComboRule==CR_None) ComboSta=-1;
if ((ReadHistoryMsg)||(IsZoneClear)) ComboSta=0;
if (IsCascade) ComboSta=max(ComboSta,0);
if (ComboSta>0) {
C2ComboRem = max(0,C2ComboRem);
if (ComboRule==CR_C2)
C2ComboRem=max(0,C2ComboRem+C2ComboBase[min(int(C2ComboBase.size())-1,Combo)]+Lines*C2ComboBonus[min(int(C2ComboBonus.size())-1,Combo)]);
Combo += ComboSta;
if (ComboRule==CR_C2) {
ComboText=Combo; ComboAge=0;
}
else if (Combo>1) {
ComboText=Combo-1; ComboAge=0;
}
}
else if (ComboSta<0) {
if (ComboRule==CR_C2) C2ComboRem=max(0,C2ComboRem-390);
else {
if (Combo>1) ComboText=ComboAge=0;
Combo = 0;
}
}
if (!RealLines) AllClear=false;
if (AllClearRule==AR_None) AllClear=false;
int B2BSta = 0;
if (RealLines) B2BSta=(((Lines>3)&&(Mod8<2))||(SpinLev))?1:-1;
if (AllClear) {
if ((AllClearRule==AR_IO)||(AllClearRule==AR_Default)) B2BSta=max(B2BSta,1);
if (AllClearRule==AR_QP) B2BSta=max(B2BSta,2);
}
if (Chain>1) B2BSta=max(B2BSta,0);
if (IsZoneClear) B2BSta=0;
int PrevB2B = B2B;
if (B2BRule==BR_Techmino) {
if (RealLines) {
if (SpinLev) B2BSta=max(20,50*Lines+30*(Lines>2))*2/max(2,5-SpinLev);
else if (Lines>3) B2BSta=(Lines-1)*50;
else if ((AllClear)&&(TLine>4)) B2BSta=800;
else if (AllClear) B2BSta=0;
else B2BSta=-250;
}
else {
if (SpinLev) B2BSta=20;
else B2BSta=-min(max(0,B2B-800),40);
}
}
if (GarbFuse) B2BSta=max(B2BSta,0);
if ((Mod8==2)&&(SpinLev)&&(!Lines)&&(B2B>4)) B2BSta=max(B2BSta,1);
if ((Mod6==2)&&(!QPBlighted)&&(!DigVal)) B2BSta=min(B2BSta,0);
if (Mod6==2) B2BSta=min(B2BSta,0);
if (B2BRule==BR_None) B2BSta=-1;
//if (Spin) B2BSta=1;
int CurScore = BaseScore(Lines,SpinLev);
int Defense = 0;
bool B2BDig = false;
if (ReadHistoryMsg) B2BSta=0;
if (B2BRule==BR_Techmino) {
if (B2BSta>0) {
if (SpinLev) {
if (PrevB2B>=50) {
BaseAttack += 1+(Lines>2);
if (PrevB2B>800) {
BaseAttack += 0.5*Lines;
++Defense;
}
}
}
else if (PrevB2B>800) {
BaseAttack*=1.5; ++Defense;
}
else if (PrevB2B>=50) ++BaseAttack;
B2B = min(1000,B2B+B2BSta);
}
else B2B=max(0,B2B+B2BSta);
if (B2B!=PrevB2B) {
B2BText=B2B; B2BAge=0;
}
}
else if (B2BSta>0) {
B2B += B2BSta;
if (B2BRule==BR_Chain) {
if (int(floor(GetB2BAttack(PrevB2B-1)))<int(floor(GetB2BAttack(B2B-1)))) {
B2BBlinkRem=600; AddB2BParticle(0xFFE211);
}
}
if (DigVal) B2BDig=true;
if ((PrevB2B>0)&&((SpinLev)||(Lines>3))) {
CurScore = CurScore*3/2;
if (RealLines) BaseAttack+=GetB2BAttack(B2B-1);
if (Mod8==2) {
if (Lines) ++BaseAttack;
else if (B2B>4) BaseAttack+=2;
}
}
if (B2B>1) {
B2BText=B2B-1; B2BAge=0;
}
if ((B2B>4)&&((B2BRule==BR_Surge)||(B2BRule==BR_QP))) AddB2BParticle(B2BColor(B2B-1));
}
else if (B2BSta<0) {
if (B2B>1) {
if (B2B>4) {
if (B2BRule==BR_Surge) {
Surge=B2B-1; AddB2BParticle(0xFFFFFF,2);
}
if (B2BRule==BR_QP) {
Surge=B2B-4; AddB2BParticle(0xFFFFFF,2);
}
}
B2BText=0; B2BAge=0;
if (B2BRule==BR_Chain) {
B2BBlinkRem=600; AddB2BParticle(0x888888);
}
}
B2B = 0;
}
if (AllClear) CurScore+=3500;
if ((Combo>1)&&(RealLines)) CurScore+=(Combo-1)*50;
double MultiplerRes = (RealLines)?GetMultiplerComboAttack(Combo-1,BaseAttack,Lines):BaseAttack;
double FlatRes = BaseAttack+((RealLines)?GetComboAttack(Combo-1):0);
if ((ComboRule==CR_Techmino)||(ComboRule==CR_Default)) FlatRes=max(FlatRes-BaseAttack,BaseAttack);
CalcAttack = max(MultiplerRes,FlatRes);
CalcAttack += Surge;
if (B2BDig) {
if (DigBonus==2) ++CalcAttack;
if (DigBonus==1) ++Defense;
}
if ((SingleBonus)&&(Lines==1)&&(Combo<=1)&&(B2B<1)) {
if (!QPHardmode()) ++CalcAttack;
}
if (AllClear) {
++TAC;
if (AllClearRule==AR_Default) {
CalcAttack+=(LY>>1); Defense+=LY-(LY>>1);
}
if (AllClearRule==AR_IO) CalcAttack+=5;
if (AllClearRule==AR_QP) CalcAttack+=3;
if (AllClearRule==AR_Guildline) CalcAttack+=10;
if (AllClearRule==AR_Arcade) CalcAttack*=2;
if (AllClearRule==AR_Techmino) CalcAttack=max(CalcAttack,double(min(16,6+2*TAC)));
}
if ((Mod6==2)&&(RealLines)) {
if ((!QPBlighted)&&(!DigVal)) CalcAttack=Surge;
if (QPBlighted) {
CalcAttack*=1.75;
if (!DigVal) {
++CalcAttack; QPBlighted=false; AddB2BParticle(0xFFFFFF,1);
}
}
if (DigVal) {
QPBlighted=true; AddB2BParticle(0xFFE211,1);
}
}
int Attack = max(0,int(floor(CalcAttack+0.001)));
if (IntRule==IR_Ceil) Attack=max(0,int(ceil(CalcAttack-0.001)));
double rem = CalcAttack-Attack;
if (IntRule==IR_Random) {
if (randf()<rem) ++Attack;
}
if (IntRule==IR_Accumulate) {
AttackAcc += rem;
if (AttackAcc>=0.9999) {
++Attack; AttackAcc-=1.0;
}
}
Attack = max(Attack,0);
if (CurZone) {
ZoneAttack+=Attack; Attack=0;
}
else if (ZoneAttack) {
Surge=Attack=Surge+ZoneAttack; ZoneAttack=0;
}
if (!TargetSta) TAttack+=Attack;
LastAttack = Attack;
if (CurScore) {
double sz = 0.8*(1.0+0.1*sqrt(max(0.0,CurScore*0.005)));
if (!TargetSta) TScore+=ll(CurScore)*ll(max(1,Level+1));
if (!QPMode)
AddFloatText("+"+IToS(ll(CurScore)*ll(max(1,Level+1))), p.GetColor(), sz, 0.08, 0.15, 0.1,
SX+1, LY*0.5-0.4, 0.3, 0, 0, 0);
}
int CancelMax = 0;
for (int i=0; i<AttackIn.size(); ++i) {
if ((AttackIn[i].Delay>GarbageDelay-GarbagePass)&&((!QPMode)||(!WindUpCD))) break;
CancelMax = i+1;
}
if (TPiece<=OpenerProtect) Defense+=max(0,min(Attack,CancelMax-Defense-Attack));
if (Mod5==1) Defense+=Attack;
int Cancel = min(Attack+Defense,int(CancelMax));
if (Defense>=Cancel) Defense-=Cancel;
else {
Attack-=Cancel-Defense; Defense=0;
}
for (int i=0; i<min(Cancel,GarbagePreview); ++i) {
for (int j=1; j<=LY; ++j) {
if (!AttackIn[i].B[j]) continue;
int clr = Mix(0xFFFFFF,abs(AttackIn[i].B[j]),0.2);
clr = Mix(clr,BackgroundColor,max(0.2,0.8-0.1*i));
double sz=0.2+randf()*0.1, th=randf()*2.0*acos(-1.0);
double d=randf(), x=SX-(-i-0.5)+0.5+cos(th)*d, y=j-0.5+sin(th)*d;
AddParticle(0, 4, clr, sz, sz*3.0,
x, y, cos(th), sin(th), 0, 0, randf()*acos(-1.0), 0.3);
}
}
for (int i=Cancel; i<AttackIn.size(); ++i) AttackIn[i-Cancel]=AttackIn[i];
for (int i=0; i<Cancel; ++i) AttackIn.pop_back();
int clr = 0x888888;
if (Surge) clr=0x00FFCC;
else if (SpinLev) clr=p.GetColor();
else if (Combo>1) clr=0x39C5BB;
if (Defense) AddAttackText(Defense,0,0x888888,cpx,cpy,SpinLev,0.5);
if (Cancel) AddAttackText(Cancel,clr,0xDDDDDD,cpx,cpy,SpinLev);
if (Attack) {
int Split = (Surge)?min(30,max(3,Surge/10)):1;
//if (QPMode) Split*=2;
AddAttackText(Attack, 0xDDDDDD, clr, cpx, cpy, SpinLev);
/*if ((QPMode)&&(Attack>=2)) {
int d = rand()%6;
if (d<2) Split=max(Split,4);
if (d<4) Split=max(Split,2);
}*/
GiveQPScore(Attack*1000LL, true, true, p.GetColor());
if (TargetType==TT_Backfire) Attack=max(0,Attack-Surge);
for (int i=0; i<Split; ++i) {
int val = Attack/Split+(i<Attack%Split);
AttackSeq(val);
}
}
if (QPMode) {
if ((Attack)||(Cancel)||(Lines)) {
if (QPNextLevelDistance()<=2000LL) GiveQPScore(3000LL,true,false,p.GetColor());
}
if ((Lines)&&(Mod9<2)) GiveQPExp(500+10000*(((Mod8==2)&&(!SpinLev))?1:Lines));
if (Cancel) GiveQPExp(500+10000*(((Mod5==2)||(Mod9==2)||(ModD==2))?0:Cancel));
if (Attack) GiveQPExp(500+10000*min(Attack,10000));
}
SpinSta=RotSta=false;
if (Mutate) {
for (int i=PreTLine+1; i<=TLine; ++i) {
if (i>=AddID*AddID/2+AddID*3) {
++AddID;
if (Gen.Pool.size()<1000) Gen.Pool.push_back(GetMutate(P_A));
}
else if ((Gen.Pool.size())&&(i%1==0)) {
int p = MutatePos%Gen.Pool.size();
Gen.Pool[p] = GetMutate(Gen.Pool[p]);
++MutatePos; if (MutatePos>=Gen.Pool.size()) MutatePos=0;
}
}
}
}
void ActivateGarbage() {
int tot = 0;
if (GarbagePush) {
for (GarbageLayer &o : AttackIn) {
if ((GarbageGap>=0)&&(tot>=GarbageGap)) break;
if (!o.Delay) o.Delay=-1;
++tot;
}
}
else {
while ((!AttackIn.empty())&&(AttackIn[0].Delay<=0)&&((!CurZone)||(!ZoneReq))) {
if ((GarbageGap>=0)&&(tot>=GarbageGap)) break;
++tot;
GarbageLayer o = AttackIn[0];
AddGarbage(o);
for (int i=1; i<AttackIn.size(); ++i) AttackIn[i-1]=AttackIn[i];
AttackIn.pop_back();
}
}
}
void PostAREProcess() {
int Lines = ClearLines();
FallTime=0; HoldRem=HoldLen;
for (int i=1; i<=LX; ++i) FallDest[i]=0;
int Height = 0;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (B[i][j]<0) Height=max(Height,i);
}
}
if (Height) LineAfterPC+=Lines;
else LineAfterPC=0;
bool f = false;
if (GarbageActive==GA_Default) f=(!Lines);
if (GarbageActive==GA_Attack) f=(!LastAttack);
if ((GarbageActive==GA_None)||(GarbageActive==GA_Instant)) f=true;
if (ModS) {
int TargetLY = min(20,max(4,4+TLine/20));
while (LY<TargetLY) {
ChangeSize(LX,LY+1,SX+1,(LY&1)+1); AddNotice(IToS(LY)+"*"+IToS(LY),0x66CCFF);
}
}
if (f) ActivateGarbage();
if ((CurZone)||(IsZoneClear)) ZoneProgress=0;
else {
ZoneAttack=0; ZoneProgress+=Lines;
}
IsZoneClear = false;
}
void PrintStrL(string str, double x, double y, double sz, int clr, double bd=0.12, double dis=1.0, string eff="", double th=0.0, double sc=0.0) {
PaintManager::PrintStrL(str, PX+K*x, PY+K*y, K*sz*0.66, clr, bd, dis, eff, th, sc);
}
void PrintStrR(string str, double x, double y, double sz, int clr, double bd=0.12, double dis=1.0, string eff="", double th=0.0, double sc=0.0) {
PaintManager::PrintStrR(str, PX+K*x, PY+K*y, K*sz*0.66, clr, bd, dis, eff, th, sc);
}
void PrintAction(string str, double x, double y, double sz, int clr, double bd=0.12, double dis=1.0, string eff="", double th=0.0, double sc=0.0) {
if (HideStat) PrintStrM(str, x, LY*0.5-0.1, sz, clr, bd, dis, eff, th, sc);
else PrintStrR(str, x, y, sz, clr, bd, dis, eff, th, sc);
}
void PrintStrM(string str, double x, double y, double sz, int clr, double bd=0.12, double dis=1.0, string eff="", double th=0.0, double sc=0.0) {
PaintManager::PrintStrM(str, PX+K*x, PY+K*y, K*sz*0.66, clr, bd, dis, eff, th, sc);
}
void Rect(double x, double y, double dx, double dy, int clr, double th=0.0, double rx=0.0, double ry=0.0) {
PaintManager::Rect(PX+K*x, PY+K*y, dx*K, dy*K, clr, th, PX+K*rx, PY+K*ry);
}
void Square(double x, double y, double d, int clr, double th=0.0, double rx=0.0, double ry=0.0) {
Rect(x, y, d, d, clr, th, rx, ry);
}
void Poly(double x, double y, double sz, int n, int clr, double th=0.0) {
PaintManager::Poly(PX+K*x, PY+K*y, sz*K, n, clr, th);
}
#define sq(xx,ss,clr) Square(x+sz*(xx),y+sz*(xx),sz*(ss),clr,th,rx,ry)
#define rec(xx,yy,sx,sy,clr) Rect(x+sz*(xx),y+sz*(yy),sz*(sx),sz*(sy),clr,th,rx,ry)
void PaintTile(double x, double y, int clr, double sz=1.0, EBlockStyle Style=S_Default, double th=0.0, double rx=0.0, double ry=0.0, bool u=false, bool d=false, bool l=false, bool r=false) {
Square(x, y, sz, clr, th, rx, ry);
if ((K*double(GetSize())<8.0)) return;
if (1) {
if ((Style==S_Default)||(Style==S_Active)) {
sq(0, 1, Mix(0xFFFFFF,clr,0.1));
sq(0.1, 0.9, Mix(0x000000,clr,0.2));
sq(0.1, 0.8, clr);
sq(0.2, 0.65, Mix(0xFFFFFF,clr,0.2));
sq(0.2, 0.6, Mix(0x000000,clr,0.05));
sq(0.3, 0.4, Mix(0xFFFFFF,clr,0.2));
sq(0.35, 0.3, clr);
if ((u)&&(!r)) rec(0,0.9,0.1,0.1,Mix(0x000000,clr,0.2));
if ((l)&&(!d)) rec(0.9,0,0.1,0.1,Mix(0x000000,clr,0.2));
}
if (Style==S_Garbage) {
sq(0, 1, Mix(0xFFFFFF,clr,0.1));
sq(0.1, 0.9, Mix(0x000000,clr,0.2));
sq(0.1, 0.8, clr);
sq(0.2, 0.6, Mix(0x000000,clr,0.05));
sq(0.25, 0.5, Mix(0x000000,clr,0.1));
sq(0.3, 0.4, Mix(0x000000,clr,0.15));
}
}
if (u) rec(0,0.1,0.1,0.8,clr);