/*
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;
}
Example #5
0
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;
}
Example #6
0
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;
}
Example #7
0
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;
			}
}
Example #8
0
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);
}
Example #12
0
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;
}