/* Help-function. Turns a start->goal-request into a will defined request. */ unsigned int CPathManager::RequestPath(const MoveData* moveData, float3 startPos, float3 goalPos, float goalRadius, CSolidObject* caller) { startPos.CheckInBounds(); goalPos.CheckInBounds(); if (startPos.x > gs->mapx * SQUARE_SIZE - 5) { startPos.x = gs->mapx * SQUARE_SIZE - 5; } if (goalPos.z > gs->mapy * SQUARE_SIZE - 5) { goalPos.z = gs->mapy * SQUARE_SIZE - 5; } // Create an estimator definition. CRangedGoalWithCircularConstraint* rangedGoalPED = SAFE_NEW CRangedGoalWithCircularConstraint(startPos,goalPos, goalRadius, 3, 2000); // Make request. return RequestPath(moveData, startPos, rangedGoalPED, goalPos, caller); }
/* Storing data and doing some top-administration. */ IPath::SearchResult CPathEstimator::GetPath(const MoveData& moveData, float3 start, const CPathFinderDef& peDef, Path& path, unsigned int maxSearchedBlocks) { // START_TIME_PROFILE; start.CheckInBounds(); //Clear path. path.path.clear(); path.pathCost = PATHCOST_INFINITY; //Initial calculations. maxBlocksToBeSearched = std::min(maxSearchedBlocks, (unsigned int) MAX_SEARCHED_BLOCKS); startBlock.x = (int)(start.x / BLOCK_PIXEL_SIZE); startBlock.y = (int)(start.z / BLOCK_PIXEL_SIZE); startBlocknr = startBlock.y * nbrOfBlocksX + startBlock.x; int2 goalBlock; goalBlock.x=peDef.goalSquareX/BLOCK_SIZE; goalBlock.y=peDef.goalSquareZ/BLOCK_SIZE; CPathCache::CacheItem* ci=pathCache->GetCachedPath(startBlock,goalBlock,peDef.sqGoalRadius,moveData.pathType); if(ci){ // logOutput.Print("Using cached path %i",BLOCK_SIZE); path=ci->path; /* if(BLOCK_SIZE==8){ END_TIME_PROFILE("Estimater 8"); }else{ END_TIME_PROFILE("Estimater 32"); }*/ return ci->result; } // logOutput.Print("----Creating new path %i",BLOCK_SIZE); //Search SearchResult result = InitSearch(moveData, peDef); //If successful, generate path. if(result == Ok || result == GoalOutOfRange) { FinishSearch(moveData, path); pathCache->AddPath(&path,result,startBlock,goalBlock,peDef.sqGoalRadius,moveData.pathType); //only add succesfull paths to the cache if(PATHDEBUG) { logOutput << "PE: Search completed.\n"; logOutput << "Tested blocks: " << testedBlocks << "\n"; logOutput << "Open blocks: " << (float)(openBlockBufferPointer - openBlockBuffer) << "\n"; logOutput << "Path length: " << (int)(path.path.size()) << "\n"; logOutput << "Path cost: " << path.pathCost << "\n"; } } else { if(PATHDEBUG) { logOutput << "PE: Search failed!\n"; logOutput << "Tested blocks: " << testedBlocks << "\n"; logOutput << "Open blocks: " << (float)(openBlockBufferPointer - openBlockBuffer) << "\n"; } } /* if(BLOCK_SIZE==8){ END_TIME_PROFILE("Estimater 8"); }else{ END_TIME_PROFILE("Estimater 32"); }*/ return result; }
void CGroundDecalHandler::AddExplosion(float3 pos, float damage, float radius) { if (decalLevel == 0) return; float height = pos.y - ground->GetHeight2(pos.x, pos.z); if (height >= radius) return; pos.y -= height; radius -= height; if (radius < 5) return; if (damage > radius * 30) damage = radius * 30; damage *= (radius) / (radius + height); if (radius > damage * 0.25f) radius = damage * 0.25f; if (damage > 400) damage = 400 + sqrt(damage - 399); pos.CheckInBounds(); Scar* s = new Scar; s->pos = pos; s->radius = radius * 1.4f; s->creationTime = gs->frameNum; s->startAlpha = max(50.f, min(255.f, damage)); float lifeTime = decalLevel * (damage) * 3; s->alphaFalloff = s->startAlpha / (lifeTime); s->lifeTime = (int) (gs->frameNum + lifeTime); s->texOffsetX = (gu->usRandInt() & 128)? 0: 0.5f; s->texOffsetY = (gu->usRandInt() & 128)? 0: 0.5f; s->x1 = (int) max(0.f, (pos.x - radius) / 16.0f ); s->x2 = (int) min(float(gs->hmapx - 1), (pos.x + radius) / 16.0f + 1); s->y1 = (int) max(0.f, (pos.z - radius) / 16.0f ); s->y2 = (int) min(float(gs->hmapy - 1), (pos.z + radius) / 16.0f + 1); s->basesize = (s->x2 - s->x1) * (s->y2 - s->y1); s->overdrawn = 0; s->lastTest = 0; GML_STDMUTEX_LOCK(scar); // AddExplosion scarsToBeAdded.push_back(s); }
/* * stores data and does some top-administration */ IPath::SearchResult CPathEstimator::GetPath(const MoveData& moveData, float3 start, const CPathFinderDef& peDef, Path& path, unsigned int maxSearchedBlocks) { start.CheckInBounds(); // clear the path path.path.clear(); path.pathCost = PATHCOST_INFINITY; // initial calculations maxBlocksToBeSearched = std::min(maxSearchedBlocks, (unsigned int) MAX_SEARCHED_BLOCKS); startBlock.x = (int)(start.x / BLOCK_PIXEL_SIZE); startBlock.y = (int)(start.z / BLOCK_PIXEL_SIZE); startBlocknr = startBlock.y * nbrOfBlocksX + startBlock.x; int2 goalBlock; goalBlock.x = peDef.goalSquareX / BLOCK_SIZE; goalBlock.y = peDef.goalSquareZ / BLOCK_SIZE; CPathCache::CacheItem* ci = pathCache->GetCachedPath(startBlock, goalBlock, peDef.sqGoalRadius, moveData.pathType); if (ci) { // use a cached path if we have one path = ci->path; return ci->result; } // oterhwise search SearchResult result = InitSearch(moveData, peDef); // if search successful, generate new path if (result == Ok || result == GoalOutOfRange) { FinishSearch(moveData, path); // only add succesful paths to the cache pathCache->AddPath(&path, result, startBlock, goalBlock, peDef.sqGoalRadius, moveData.pathType); if (PATHDEBUG) { LogObject() << "PE: Search completed.\n"; LogObject() << "Tested blocks: " << testedBlocks << "\n"; LogObject() << "Open blocks: " << (float)(openBlockBufferPointer - openBlockBuffer) << "\n"; LogObject() << "Path length: " << (int)(path.path.size()) << "\n"; LogObject() << "Path cost: " << path.pathCost << "\n"; } } else { if (PATHDEBUG) { LogObject() << "PE: Search failed!\n"; LogObject() << "Tested blocks: " << testedBlocks << "\n"; LogObject() << "Open blocks: " << (float)(openBlockBufferPointer - openBlockBuffer) << "\n"; } } return result; }
float CGround::TrajectoryGroundCol(float3 from, float3 flatdir, float length, float linear, float quadratic) { from.CheckInBounds(); float3 dir(flatdir.x, linear, flatdir.z); for (float l = 0.0f; l < length; l += 8.0f) { float3 pos(from + dir * l); pos.y += quadratic * l * l; if (GetApproximateHeight(pos.x, pos.z) > pos.y) { return l; } } return -1; }
float CGround::TrajectoryGroundCol(float3 from, float3 flatdir, float length, float linear, float quadratic) { from.CheckInBounds(); float3 dir(flatdir.x,linear,flatdir.z); // float3 oldpos=from; for(float l=0;l<length;l+=8){ float3 pos(from+dir*l); pos.y+=quadratic*l*l; if(GetApproximateHeight(pos.x,pos.z)>pos.y){ return l; } // geometricObjects->AddLine(pos,oldpos,3,0,16); // oldpos=pos; } return -1; }
void CQuadField::GetQuads(float3 pos,float radius, int*& dst) { pos.CheckInBounds(); int maxx = std::min(((int)(pos.x + radius)) / QUAD_SIZE + 1, numQuadsX - 1); int maxz = std::min(((int)(pos.z + radius)) / QUAD_SIZE + 1, numQuadsZ - 1); int minx = std::max(((int)(pos.x - radius)) / QUAD_SIZE, 0); int minz = std::max(((int)(pos.z - radius)) / QUAD_SIZE, 0); if (maxz < minz || maxx < minx) return; float maxSqLength = (radius + QUAD_SIZE * 0.72f) * (radius + QUAD_SIZE * 0.72f); for (int z = minz; z <= maxz; ++z) for (int x = minx; x <= maxx; ++x) if ((pos - float3(x * QUAD_SIZE + QUAD_SIZE * 0.5f, 0, z * QUAD_SIZE + QUAD_SIZE * 0.5f)).SqLength2D() < maxSqLength) { *dst = z * numQuadsX + x; ++dst; } }
vector<int> CQuadField::GetQuads(float3 pos,float radius) { pos.CheckInBounds(); vector<int> ret; int maxx = std::min(((int)(pos.x + radius)) / QUAD_SIZE + 1, numQuadsX - 1); int maxz = std::min(((int)(pos.z + radius)) / QUAD_SIZE + 1, numQuadsZ - 1); int minx = std::max(((int)(pos.x - radius)) / QUAD_SIZE, 0); int minz = std::max(((int)(pos.z - radius)) / QUAD_SIZE, 0); if (maxz < minz || maxx < minx) return ret; float maxSqLength = (radius + QUAD_SIZE * 0.72f) * (radius + QUAD_SIZE * 0.72f); ret.reserve((maxz - minz) * (maxx - minx)); for (int z = minz; z <= maxz; ++z) for (int x = minx; x <= maxx; ++x) if ((pos - float3(x * QUAD_SIZE + QUAD_SIZE * 0.5f, 0, z * QUAD_SIZE + QUAD_SIZE * 0.5f)).SqLength2D() < maxSqLength) ret.push_back(z * numQuadsX + x); return ret; }
vector<int> CQuadField::GetQuads(float3 pos,float radius) { pos.CheckInBounds(); vector<int> ret; int maxx=min(((int)(pos.x+radius))/QUAD_SIZE+1,numQuadsX-1); int maxy=min(((int)(pos.z+radius))/QUAD_SIZE+1,numQuadsZ-1); int minx=max(((int)(pos.x-radius))/QUAD_SIZE,0); int miny=max(((int)(pos.z-radius))/QUAD_SIZE,0); if(maxy<miny || maxx<minx) return ret; float maxSqLength=(radius+QUAD_SIZE*0.72f)*(radius+QUAD_SIZE*0.72f); ret.reserve((maxy-miny)*(maxx-minx)); for(int y=miny;y<=maxy;++y) for(int x=minx;x<=maxx;++x) if((pos-float3(x*QUAD_SIZE+QUAD_SIZE*0.5f,0,y*QUAD_SIZE+QUAD_SIZE*0.5f)).SqLength2D()<maxSqLength) ret.push_back(y*numQuadsX+x); return ret; }
void CQuadField::GetQuads(float3 pos,float radius, int*& dst) { pos.CheckInBounds(); int maxx=min(((int)(pos.x+radius))/QUAD_SIZE+1,numQuadsX-1); int maxy=min(((int)(pos.z+radius))/QUAD_SIZE+1,numQuadsZ-1); int minx=max(((int)(pos.x-radius))/QUAD_SIZE,0); int miny=max(((int)(pos.z-radius))/QUAD_SIZE,0); if(maxy<miny || maxx<minx) return; int* org = dst; float maxSqLength=(radius+QUAD_SIZE*0.72f)*(radius+QUAD_SIZE*0.72f); for(int y=miny;y<=maxy;++y) for(int x=minx;x<=maxx;++x) if((pos-float3(x*QUAD_SIZE+QUAD_SIZE*0.5f,0,y*QUAD_SIZE+QUAD_SIZE*0.5f)).SqLength2D()<maxSqLength) { *dst = y*numQuadsX+x; ++dst; } }
void CGroundDecalHandler::AddExplosion(float3 pos, float damage, float radius) { if(decalLevel==0) return; float height=pos.y-ground->GetHeight2(pos.x,pos.z); if(height>=radius) return; pos.y-=height; radius-=height; if(radius<5) return; if(damage>radius*30) damage=radius*30; damage*=(radius)/(radius+height); if(radius>damage*0.25) radius=damage*0.25; if(damage>400) damage=400+sqrt(damage-399); pos.CheckInBounds(); Scar* s=new Scar; s->pos=pos; s->radius=radius*1.4; s->creationTime=gs->frameNum; s->startAlpha=max(50,min(255,damage)); float lifeTime=decalLevel*(damage)*3; s->alphaFalloff=s->startAlpha/(lifeTime); s->lifeTime=gs->frameNum+lifeTime; s->texOffsetX=(gu->usRandInt()&128)?0:0.5f; s->texOffsetY=(gu->usRandInt()&128)?0:0.5f; s->x1=max(0,(pos.x-radius)/16.0f); s->x2=min(gs->hmapx-1,(pos.x+radius)/16.0f+1); s->y1=max(0,(pos.z-radius)/16.0f); s->y2=min(gs->hmapy-1,(pos.z+radius)/16.0f+1); s->basesize=(s->x2-s->x1)*(s->y2-s->y1); s->overdrawn=0; s->lastTest=0; TestOverlaps(s); int x1=s->x1/16; int x2=min(scarFieldX-1,s->x2/16); int y1=s->y1/16; int y2=min(scarFieldY-1,s->y2/16); for(int y=y1;y<=y2;++y){ for(int x=x1;x<=x2;++x){ std::set<Scar*>* quad=&scarField[y*scarFieldX+x]; quad->insert(s); } } scars.push_back(s); }
float CGround::LineGroundCol(float3 from, float3 to) { float savedLength = 0.0f; if (from.z > float3::maxzpos && to.z < float3::maxzpos) { // a special case since the camera in overhead mode can often do this float3 dir = to - from; float maxLength = dir.Length(); dir /= maxLength; savedLength = -(from.z - float3::maxzpos) / dir.z; from += dir * savedLength; } from.CheckInBounds(); float3 dir = to - from; float maxLength = dir.Length(); dir /= maxLength; if (from.x + dir.x * maxLength < 1.0f) maxLength = (1.0f - from.x) / dir.x; else if (from.x + dir.x * maxLength > float3::maxxpos) maxLength = (float3::maxxpos - from.x) / dir.x; if (from.z + dir.z * maxLength < 1.0f) maxLength = (1.0f - from.z) / dir.z; else if (from.z + dir.z * maxLength > float3::maxzpos) maxLength = (float3::maxzpos - from.z) / dir.z; to = from + dir * maxLength; const float dx=to.x-from.x; const float dz=to.z-from.z; float xp=from.x; float zp=from.z; float ret; float xn,zn; bool keepgoing=true; if((floor(from.x/SQUARE_SIZE)==floor(to.x/SQUARE_SIZE)) && (floor(from.z/SQUARE_SIZE)==floor(to.z/SQUARE_SIZE))) { ret = LineGroundSquareCol(from,to,(int)floor(from.x/SQUARE_SIZE),(int)floor(from.z/SQUARE_SIZE)); if(ret>=0) { return ret; } } else if(floor(from.x/SQUARE_SIZE)==floor(to.x/SQUARE_SIZE)) { while(keepgoing) { ret = LineGroundSquareCol(from,to,(int)floor(xp/SQUARE_SIZE),(int)floor(zp/SQUARE_SIZE)); if(ret>=0) { return ret+savedLength; } keepgoing=fabs(zp-from.z)<fabs(dz); if(dz>0) zp+=SQUARE_SIZE; else zp-=SQUARE_SIZE; } // if you hit this the collision detection hit an infinite loop assert(!keepgoing); } else if(floor(from.z/SQUARE_SIZE)==floor(to.z/SQUARE_SIZE)) { while(keepgoing) { ret = LineGroundSquareCol(from,to,(int)floor(xp/SQUARE_SIZE),(int)floor(zp/SQUARE_SIZE)); if(ret>=0) { return ret+savedLength; } keepgoing=fabs(xp-from.x)<fabs(dx); if(dx>0) xp+=SQUARE_SIZE; else xp-=SQUARE_SIZE; } // if you hit this the collision detection hit an infinite loop assert(!keepgoing); } else { while(keepgoing) { float xs, zs; // Push value just over the edge of the square // This is the best accuracy we can get with floats: // add one digit and (xp*constant) reduces to xp itself // This accuracy means that at (16384,16384) (lower right of 32x32 map) // 1 in every 1/(16384*1e-7f/8)=4883 clicks on the map will be ignored. if (dx>0) xs = floor(xp*1.0000001f/SQUARE_SIZE); else xs = floor(xp*0.9999999f/SQUARE_SIZE); if (dz>0) zs = floor(zp*1.0000001f/SQUARE_SIZE); else zs = floor(zp*0.9999999f/SQUARE_SIZE); ret = LineGroundSquareCol(from, to, (int)xs, (int)zs); if(ret>=0) { return ret+savedLength; } keepgoing=fabs(xp-from.x)<fabs(dx) && fabs(zp-from.z)<fabs(dz); if(dx>0) { // distance xp to right edge of square (xs,zs) divided by dx, xp += xn*dx puts xp on the right edge xn=(xs*SQUARE_SIZE+SQUARE_SIZE-xp)/dx; } else { // distance xp to left edge of square (xs,zs) divided by dx, xp += xn*dx puts xp on the left edge xn=(xs*SQUARE_SIZE-xp)/dx; } if(dz>0) { // distance zp to bottom edge of square (xs,zs) divided by dz, zp += zn*dz puts zp on the bottom edge zn=(zs*SQUARE_SIZE+SQUARE_SIZE-zp)/dz; } else { // distance zp to top edge of square (xs,zs) divided by dz, zp += zn*dz puts zp on the top edge zn=(zs*SQUARE_SIZE-zp)/dz; } // xn and zn are always positive, minus signs are divided out above // this puts (xp,zp) exactly on the first edge you see if you look from (xp,zp) in the (dx,dz) direction if(xn<zn) { xp+=xn*dx; zp+=xn*dz; } else { xp+=zn*dx; zp+=zn*dz; } } } return -1; }