📄 m_entity.cpp
字号:
//0-Present Direction, 1-Opposit Direction, 2-Other Dir 1, 3-Other Dir 2
float fChance[4]={0,0,0,0};
float tmpChance = 0;
int deltaX=0, deltaY=0, accessible=0, accessList=0, nCnt=0;
//STEP 1. If present direction is STEADY, all possible direction go equal chance
if(thisEnt->nDirection==DIR_STEADY)
{//this should only happens when it respawn
mb[0] = thisMap->GetMapBlockInfo(thisEnt->nPosX,thisEnt->nPosY-1);
mb[1] = thisMap->GetMapBlockInfo(thisEnt->nPosX,thisEnt->nPosY+1);
mb[2] = thisMap->GetMapBlockInfo(thisEnt->nPosX-1,thisEnt->nPosY);
mb[3] = thisMap->GetMapBlockInfo(thisEnt->nPosX+1,thisEnt->nPosY);
//check all accessible direction
for(nCnt=0; nCnt<4; nCnt++)
{
if(mb[nCnt]->nBlockType!=B_WALL)
{
dir[nCnt] = nCnt+1;//zero fix, as c++ starts from 0 not 1
accessible++;
accessList+=(1<<nCnt);//0001 0010 0100 1000
}
}
//calculate equal chances. Sorry, some complicated gramma... @_@
for(nCnt=0; nCnt<4; nCnt++)
{//that means:
//(chance of this direction) = (1/total num of accessible direction) *
//(is this direction accessible? 1-yes, 0-no)
fChance[nCnt] = (1/float(accessible)) * (((accessList^(1<<nCnt))&(1<<nCnt))?0:1);
}
if(fChance[0]==fChance[1] && fChance[1]==fChance[2]
&& fChance[2]==fChance[3] && fChance[3]==0)
{//if all direction access denied
return DIR_STEADY;
}
//go test
srand((unsigned)clockticks);
tmpChance = float(rand()%100)/100;
if(tmpChance<fChance[0])
return((curNextDir = nNextMovDir = thisEnt->nDirection = dir[0]));
if(tmpChance>=fChance[0] && tmpChance<fChance[0]+fChance[1])
return((curNextDir = nNextMovDir = thisEnt->nDirection = dir[1]));
if(tmpChance>=fChance[0]+fChance[1] && tmpChance<fChance[0]+fChance[1]+fChance[2])
return((curNextDir = nNextMovDir = thisEnt->nDirection = dir[2]));
if(tmpChance>=fChance[0]+fChance[1]+fChance[2] && tmpChance<fChance[0]+fChance[1]+fChance[2]+fChance[3])
return((curNextDir = nNextMovDir = thisEnt->nDirection = dir[3]));
}
//STEP 2. If not respawn
else
{
dir[0] = thisEnt->nDirection;
switch(dir[0])
{
case DIR_UP: dir[1] = DIR_DOWN;
dir[2] = DIR_LEFT;
dir[3] = DIR_RIGHT;
break;
case DIR_DOWN: dir[1] = DIR_UP;
dir[2] = DIR_LEFT;
dir[3] = DIR_RIGHT;
break;
case DIR_LEFT: dir[1] = DIR_RIGHT;
dir[2] = DIR_UP;
dir[3] = DIR_DOWN;
break;
case DIR_RIGHT: dir[1] = DIR_LEFT;
dir[2] = DIR_UP;
dir[3] = DIR_DOWN;
break;
}
//STEP 3. Check access
switch(thisEnt->nDirection)
{//calculate delta moves
case DIR_UP: deltaX=0; deltaY=-1; break;
case DIR_DOWN: deltaX=0; deltaY=1; break;
case DIR_LEFT: deltaX=-1; deltaY=0; break;
case DIR_RIGHT: deltaX=1; deltaY=0; break;
case DIR_STEADY: deltaX=0; deltaY=0; break;
}
//get next block info <0-UP,1-DOWN,2-LEFT,3-RIGHT>
mb[0] = thisMap->GetMapBlockInfo(thisEnt->nPosX+deltaX,thisEnt->nPosY+deltaY-1);
mb[1] = thisMap->GetMapBlockInfo(thisEnt->nPosX+deltaX,thisEnt->nPosY+deltaY+1);
mb[2] = thisMap->GetMapBlockInfo(thisEnt->nPosX+deltaX-1,thisEnt->nPosY+deltaY);
mb[3] = thisMap->GetMapBlockInfo(thisEnt->nPosX+deltaX+1,thisEnt->nPosY+deltaY);
//check access for 4 dir
for(int dirCnt=0; dirCnt<4; dirCnt++)
{
for(nCnt=0; nCnt<4; nCnt++)
{
if(dir[dirCnt]==(nCnt+1) && mb[nCnt]->nBlockType!=B_WALL)
{
accessible++;
accessList+=(1<<dirCnt);
}
}
}
if(((accessList^4)&4) && ((accessList^8)&8) && !((accessList^1)&1))
{//if both OTHER DIRECTIONs access denied,
//and PRESENT DIRECTION accessible
return((nNextMovDir=curNextDir=thisEnt->nDirection));
}//return PRESENT direction
if(((accessList^4)&4) && ((accessList^8)&8) && ((accessList^1)&1))
{//if neither OTHER DIRECTIONs nor PRESENT DIRECTION is accessible
return((nNextMovDir=curNextDir=dir[1]));
}//return OPPOSIT direction
if(!((accessList^4)&4) || !((accessList^8)&8))
{//if either OTHER DIRECTION is accessible
//set chances
if(!((accessList^4)&4) && !((accessList^8)&8))
{//if both OTHER DIRECTION are accessible
fChance[2]=fChance[3]=0.4;
}
else
{//if only one of the OTHER DIRECTIONs is accessible
if(!((accessList^4)&4))//if OTHER DIRECTION 1 accessible
fChance[2] = 0.8;
else//if OTHER DIRECTION 2 accessible
fChance[3] = 0.8;
}
if(!((accessList^1)&1) && !((accessList^2)&2))
{//if both PRESENT and OPPOSIT DIRECTIONs are accessible
fChance[0] = 0.15;
fChance[1] = 0.05;
}
else
{//if only one of them is accessible
if(!((accessList^1)&1))//if PRESENT DIRECTION accessible
fChance[0] = 0.2;
else
fChance[1] = 0.2;//if OPPOSIT DIRECTION accessible
}
}
//STEP 4. Calculate the final random next direction
srand((unsigned)clockticks);//use MILLISECOND RESOLUTION TIMER as seed
tmpChance = float(rand()%100)/100;//get a random 0.x number
if(tmpChance<fChance[0])
return((curNextDir = nNextMovDir = dir[0]));
if(tmpChance>=fChance[0] && tmpChance<fChance[0]+fChance[1])
return((curNextDir = nNextMovDir = dir[1]));
if(tmpChance>=fChance[0]+fChance[1] && tmpChance<fChance[0]+fChance[1]+fChance[2])
return((curNextDir = nNextMovDir = dir[2]));
if(tmpChance>=fChance[0]+fChance[1]+fChance[2] && tmpChance<fChance[0]+fChance[1]+fChance[2]+fChance[3])
return((curNextDir = nNextMovDir = dir[3]));
}
}
return M_ERR_UNKNOWN;//should never reach this line
}
void M_Monster::AIChangeNextMove(int nextMove)
{
nNextMovDir = nextMove;
curNextDir = nextMove;
}
//////////////////////
// M_ITEM CLASS
//////////////////////
M_Item::M_Item()
{
nScore = DEFAULT_ADDITION_SCORE;
}
bool M_Item::bDisable = M_FALSE;//static member
//////////////////////
// M_POWERDOT CLASS
//////////////////////
M_PowerDot::M_PowerDot(int x, int y)
{
thisEnt->nPosX = x;
thisEnt->nPosY = y;
thisEnt->fSpeed = 0;
thisEnt->nDirection = DIR_STEADY;
thisEnt->nTexture = T_POWER_DOT;
thisEnt->isLiving = M_FALSE;
nScore = -(DEFAULT_MONSTER_SCORE);//equals one monster's score
isActivated = M_FALSE;
nextThinkTime = -1;
}
bool M_PowerDot::Respawn()
{//if not activated and is not living
if(isActivated==M_FALSE && thisEnt->isLiving==M_FALSE)
{
thisRenderer->AddEC(thisEnt->nPosX, thisEnt->nPosY, thisEnt->nTexture);
thisEnt->isLiving = M_TRUE;
}
else
{
if(thisEnt->isLiving == M_TRUE)
return M_ERR_ALREADY_LIVING;
if(isActivated == M_TRUE)
return M_ERR_ITEM_ALREADY_USED;
}
return M_ERR_UNKNOWN;
}
bool M_PowerDot::Think(M_Sprite* sprite, MonsterNode* monsters)
{
if(thisEnt->isLiving == M_TRUE)//only when living
{
if(bDisable!=M_TRUE && nextThinkTime == -1)//not activating
{
if(sprite->Report()->nPosX == thisEnt->nPosX &&
sprite->Report()->nPosY == thisEnt->nPosY)
{
sprite->MoverState(S_POWER);//set Sprite to be POWERed
sprite->AddScore(nScore);
MonsterNode* ThisNode = monsters;
while(ThisNode!=NULL)
{
ThisNode->thisMonster->MoverState(S_WEAK);
ThisNode = ThisNode->nextMonster;
}
nextThinkTime = clockticks + 10000;
thisRenderer->AddMBC(thisEnt->nPosX, thisEnt->nPosY, T_SPACE);
isActivated = M_TRUE;
bDisable = M_TRUE;
return M_NORMAL;
}
else
{
thisRenderer->AddEC(thisEnt->nPosX, thisEnt->nPosY, thisEnt->nTexture);
return M_NORMAL;
}
}
else
{
if(nextThinkTime!=-1)
{
if(clockticks<nextThinkTime)
{
return M_NORMAL;
}
else
{
sprite->MoverState(S_NORMAL);
MonsterNode* ThisNode = monsters;
while(ThisNode!=NULL)
{
if(ThisNode->thisMonster->MoverState()!=S_NORMAL)
ThisNode->thisMonster->MoverState(S_NORMAL);
ThisNode = ThisNode->nextMonster;
}
nextThinkTime = -1;
bDisable = M_FALSE;
Kill();
return M_NORMAL;
}
}
else if(bDisable==M_TRUE) thisRenderer->AddMBC(thisEnt->nPosX,thisEnt->nPosY,T_SPACE);
}
}
return M_ERR_NOTLIVING;
}
bool M_PowerDot::Kill()
{
if(thisEnt->isLiving == M_TRUE)
{
thisEnt->isLiving = M_FALSE;
return M_NORMAL;
}
return M_ERR_NOTLIVING;
}
//////////////////////
// M_SPEEDDOT CLASS
//////////////////////
M_SpeedDot::M_SpeedDot(int x, int y)
{
thisEnt->nPosX = x;
thisEnt->nPosY = y;
thisEnt->fSpeed = 0;
thisEnt->nDirection = DIR_STEADY;
thisEnt->nTexture = T_SPEED_DOT;
thisEnt->isLiving = M_FALSE;
respawnTime = clockticks+50000;
nScore = 0;
isActivated = M_FALSE;
nextThinkTime = -1;
}
bool M_SpeedDot::Respawn()
{//if not activated and is not living
if(thisEnt->isLiving==M_FALSE && clockticks>respawnTime)
{
thisRenderer->AddEC(thisEnt->nPosX, thisEnt->nPosY, thisEnt->nTexture);
thisEnt->isLiving = M_TRUE;
}
else
{
if(thisEnt->isLiving == M_TRUE)
return M_ERR_ALREADY_LIVING;
if(clockticks<respawnTime)
return M_ERR_ITEM_NOT_READY;
}
return M_ERR_UNKNOWN;
}
bool M_SpeedDot::Think(M_Sprite* sprite, MonsterNode* monsters)
{
if(thisEnt->isLiving == M_TRUE)//only when living
{
if(bDisable!=M_TRUE && nextThinkTime == -1)
{
if(sprite->Report()->nPosX == thisEnt->nPosX &&
sprite->Report()->nPosY == thisEnt->nPosY)
{
sprite->MoverState(S_SPEED);//set Sprite to be SPEEDed
sprite->AddScore(nScore);
MonsterNode* ThisNode = monsters;
while(ThisNode!=NULL)
{
ThisNode->thisMonster->MoverState(S_WEAK);
ThisNode = ThisNode->nextMonster;
}
nextThinkTime = clockticks + 20000;
thisRenderer->AddMBC(thisEnt->nPosX, thisEnt->nPosY, T_SPACE);
bDisable = M_TRUE;
isActivated = M_TRUE;
return M_NORMAL;
}
else
{
if(clockticks>respawnTime) thisRenderer->AddEC(thisEnt->nPosX, thisEnt->nPosY, thisEnt->nTexture);
return M_NORMAL;
}
}
else
{
if(nextThinkTime!=-1)
{
if(clockticks<nextThinkTime)
{
return M_NORMAL;
}
else
{
sprite->MoverState(S_NORMAL);
MonsterNode* ThisNode = monsters;
while(ThisNode!=NULL)
{
if(ThisNode->thisMonster->MoverState()!=S_NORMAL)
ThisNode->thisMonster->MoverState(S_NORMAL);
ThisNode = ThisNode->nextMonster;
}
isActivated = M_FALSE;
bDisable = M_FALSE;
nextThinkTime = -1;
Kill();
return M_NORMAL;
}
}
else if(bDisable==M_TRUE) thisRenderer->AddMBC(thisEnt->nPosX,thisEnt->nPosY,T_SPACE);
}
}
return M_ERR_NOTLIVING;
}
bool M_SpeedDot::Kill()
{
if(thisEnt->isLiving == M_TRUE)
{
thisEnt->isLiving = M_FALSE;
respawnTime = clockticks+SPEEDDOT_RESPAWN_PERIOD;
return M_NORMAL;
}
return M_ERR_NOTLIVING;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -