SharedModel(shared_ptr<IStorm3D_Model> model_, shared_ptr<IStorm3D_Model> fadeModel_, const std::string &bones_, const std::string &idleAnimation_) : model(model_), fadeModel(fadeModel_), bones(bones_), idleAnimation(idleAnimation_), radius(0), radius2d(0) { boost::scoped_ptr<Iterator<IStorm3D_Model_Object *> > objectIterator(model->ITObject->Begin()); for(; !objectIterator->IsEnd(); objectIterator->Next()) { IStorm3D_Model_Object *object = objectIterator->GetCurrent(); if(!object) continue; IStorm3D_Mesh *mesh = object->GetMesh(); if(!mesh) continue; VC3 objectPosition = object->GetPosition(); float objectDistance = objectPosition.GetLength(); float distance = objectDistance + mesh->GetRadius(); if(distance > radius) radius = distance; float meshRadius = mesh->GetRadius(); if(meshRadius + objectDistance > radius2d) radius2d = meshRadius + objectDistance; } if(!bones.empty()) model->LoadBones(bones.c_str()); }
void VisualEffect::moveBetween(const VC3 &position_, const VC3 &endPosition, const VC3 &rotation, float alpha, float scale) { if (visualObject == NULL) return; if (effectType->getType() == VisualEffectType::VISUALEFFECT_TYPE_RAY) { this->position = (position_ + endPosition) / 2; VC3 diffVec = endPosition - position_; float raylen = diffVec.GetLength(); VC3 scalevec(1*scale,1*scale,raylen); visualObject->setScale(scalevec); visualObject->setVisibilityFactor(alpha); } visualObject->setPosition(this->position); visualObject->setRotation(rotation.x, rotation.y, rotation.z); }
bool LineAreaChecker::isPointInsideLineArea(const VC3 &point, const VC3 &lineStart, const VC3 &lineEnd, float lineWidth) { VC3 projPos = lineEnd - lineStart; float projPosLenSq = projPos.GetSquareLength(); VC3 projPosNorm = VC3(0,0,0); if (projPosLenSq > 0.00001f) { projPosNorm = projPos.GetNormalized(); } VC3 chkpos = point - lineStart; float chkposLen = chkpos.GetLength(); VC3 hitAndUnitDiff = chkpos - projPos; float hitAndUnitDiffLenSq = hitAndUnitDiff.GetSquareLength(); float lineRadiusSq = (float)(lineWidth * lineWidth); if (hitAndUnitDiffLenSq < lineRadiusSq) { return true; } if (chkposLen * chkposLen < projPosLenSq) { VC3 pipedPos = projPosNorm * chkposLen; VC3 posdiff = chkpos - pipedPos; if (posdiff.GetSquareLength() < lineRadiusSq) { return true; } } return false; }
void PositionScripting::process(util::ScriptProcess *sp, int command, int intData, char *stringData, ScriptLastValueType *lastValue, GameScriptData *gsd, Game *game) { switch(command) { case GS_CMD_SETPOSITION: { VC3 tmp(0,0,0); if (gs_coordinate_param(game->gameMap, stringData, &tmp)) { float x = tmp.x; float y = tmp.z; game->gameMap->keepWellInScaledBoundaries(&x, &y); gsd->position = VC3( x, game->gameMap->getScaledHeightAt(x,y), y); } else { sp->error("PositionScripting::process - Missing or bad setPosition parameter."); } } break; case GS_CMD_POSITIONRANDOMOFFSET: if (intData > 0) { int o1 = (game->gameRandom->nextInt() % (intData * 20 + 10)) - intData*10; int o2 = (game->gameRandom->nextInt() % (intData * 20 + 10)) - intData*10; int o3 = (game->gameRandom->nextInt() % (intData * 20 + 10)) - intData*10; gsd->position.x += (float)o1 * 0.1f; gsd->position.y += (float)o2 * 0.1f; gsd->position.z += (float)o3 * 0.1f; } else { sp->warning("PositionScripting::process - positionRandomOffset with zero parameter."); lastValue = 0; } break; case GS_CMD_MOVEPOSITIONZ: gsd->position.z += (float)intData / 100.0f; break; case GS_CMD_MOVEPOSITIONX: gsd->position.x += (float)intData / 100.0f; break; case GS_CMD_MOVEPOSITIONZFLOAT: { float floatData = *((float *)(&intData)); gsd->position.z += floatData; } break; case GS_CMD_MOVEPOSITIONXFLOAT: { float floatData = *((float *)(&intData)); gsd->position.x += floatData; } break; case GS_CMD_GETPOSITIONX: *lastValue = (int)gsd->position.x; break; case GS_CMD_GETPOSITIONZ: *lastValue = (int)gsd->position.z; break; case GS_CMD_GETPOSITIONHEIGHT: *lastValue = (int)gsd->position.y; break; case GS_CMD_GETACCURATEPOSITIONX: *lastValue = (int)(gsd->position.x * 1000.0f); break; case GS_CMD_GETACCURATEPOSITIONZ: *lastValue = (int)(gsd->position.z * 1000.0f); break; case GS_CMD_SETPOSITIONHEIGHT: if (stringData != NULL) { gsd->position.y = (float)atof(stringData); } else { sp->error("PositionScripting::process - Missing setPositionHeight parameter."); } break; case GS_CMD_SETPOSITIONHEIGHTONGROUND: { float x = gsd->position.x; float y = gsd->position.z; game->gameMap->keepWellInScaledBoundaries(&x, &y); gsd->position = VC3( x, game->gameMap->getScaledHeightAt(x,y), y); } break; case GS_CMD_POSITIONACCURATERANDOMOFFSET: if (intData > 0) { // intData values in cm int o1 = (game->gameRandom->nextInt() % (intData * 20 + 10)) - intData*10; int o2 = (game->gameRandom->nextInt() % (intData * 20 + 10)) - intData*10; int o3 = (game->gameRandom->nextInt() % (intData * 20 + 10)) - intData*10; gsd->position.x += (float)o1 * 0.1f * 0.01f; gsd->position.y += (float)o2 * 0.1f * 0.01f; gsd->position.z += (float)o3 * 0.1f * 0.01f; } else { sp->warning("PositionScripting::process - positionRandomOffset with zero parameter."); lastValue = 0; } break; case GS_CMD_MOVEPOSITIONHEIGHT: gsd->position.y += (float)intData / 100.0f; break; case GS_CMD_SETSECONDARYPOSITION: gsd->secondaryPosition = gsd->position; break; case GS_CMD_GETSECONDARYPOSITION: gsd->position = gsd->secondaryPosition; break; case GS_CMD_SETPOSITIONX: gsd->position.x = (float)*lastValue; break; case GS_CMD_SETPOSITIONZ: gsd->position.z = (float)*lastValue; break; case GS_CMD_SETACCURATEPOSITIONX: gsd->position.x = (float)*lastValue / 1000.0f; break; case GS_CMD_SETACCURATEPOSITIONZ: gsd->position.z = (float)*lastValue / 1000.0f; break; case GS_CMD_setAccuratePositionHeight: gsd->position.y = (float)*lastValue / 1000.0f; break; case GS_CMD_getAccuratePositionHeight: *lastValue = (int)(gsd->position.y * 1000.0f); break; case GS_CMD_PUSHGLOBALTEMPPOSITION: if (gs_global_temp_position_used) { sp->warning("PositionScripting::process - pushGlobalTempPosition, stack full."); } gs_global_temp_position_used = true; gs_global_temp_position = gsd->position; break; case GS_CMD_POPGLOBALTEMPPOSITION: if (!gs_global_temp_position_used) { sp->warning("PositionScripting::process - popGlobalTempPosition, stack empty."); } gsd->position = gs_global_temp_position; gs_global_temp_position_used = false; gs_global_temp_position = VC3(0,0,0); break; case GS_CMD_MOVEPOSITIONTOANGLEVALUE: { float angle = (float)(*lastValue); if (angle < 0) angle += 360; if (angle >= 360) angle -= 360; float amount= (float)intData / 100.0f; gsd->position.x += -amount * sinf(UNIT_ANGLE_TO_RAD(angle)); gsd->position.z += -amount * cosf(UNIT_ANGLE_TO_RAD(angle)); } break; case GS_CMD_ISPOSITIONINSIDEBUILDING: { VC3 pos = gsd->position; int x = game->gameMap->scaledToPathfindX(pos.x); int y = game->gameMap->scaledToPathfindY(pos.z); if (game->gameMap->isWellInScaledBoundaries(pos.x, pos.z)) { if (game->gameMap->getAreaMap()->isAreaAnyValue(x, y, AREAMASK_INBUILDING)) *lastValue = 1; else *lastValue = 0; } else { *lastValue = 0; } } break; case GS_CMD_isPositionBlockedByUnmoving: { VC3 pos = gsd->position; int x = game->gameMap->scaledToPathfindX(pos.x); int y = game->gameMap->scaledToPathfindY(pos.z); if (game->gameMap->isWellInScaledBoundaries(pos.x, pos.z)) { if (game->gameMap->getObstacleHeight(x, y) > 0 && !game->gameMap->isMovingObstacle(x, y)) *lastValue = 1; else *lastValue = 0; } else { *lastValue = 0; } } break; case GS_CMD_isPositionBlockedByUnmovingOrDoor: { VC3 pos = gsd->position; int x = game->gameMap->scaledToPathfindX(pos.x); int y = game->gameMap->scaledToPathfindY(pos.z); if (game->gameMap->isWellInScaledBoundaries(pos.x, pos.z)) { // HACK: rounded moving obstacles are actually doors if (game->gameMap->getObstacleHeight(x, y) > 0 && (!game->gameMap->isMovingObstacle(x, y) || game->gameMap->isRoundedObstacle(x, y))) *lastValue = 1; else *lastValue = 0; } else { *lastValue = 0; } } break; case GS_CMD_isPositionBlockedByMoving: { VC3 pos = gsd->position; int x = game->gameMap->scaledToPathfindX(pos.x); int y = game->gameMap->scaledToPathfindY(pos.z); if (game->gameMap->isWellInScaledBoundaries(pos.x, pos.z)) { if (game->gameMap->getObstacleHeight(x, y) > 0 && game->gameMap->isMovingObstacle(x, y)) *lastValue = 1; else *lastValue = 0; } else { *lastValue = 0; } } break; case GS_CMD_setPositionVariable: if (stringData != NULL) { bool success = sp->getScript()->setGlobalPositionVariableValue(stringData, gsd->position.x, gsd->position.y, gsd->position.z); if (!success) { sp->error("PositionScripting::process - setPositionVariable, failed to set position variable value (variable does not exist or type mismatch)."); sp->debug(stringData); } } else { sp->error("PositionScripting::process - setPositionVariable parameter missing, position variable name expected."); } break; case GS_CMD_getPositionVariable: if (stringData != NULL) { float tmpx, tmpy, tmpz; bool success = sp->getScript()->getGlobalPositionVariableValue(stringData, &tmpx, &tmpy, &tmpz); if (success) { gsd->position = VC3(tmpx, tmpy, tmpz); } else { sp->error("PositionScripting::process - getPositionVariable, failed to get position variable value (variable does not exist or type mismatch)."); sp->debug(stringData); } } else { sp->error("PositionScripting::process - getPositionVariable parameter missing, position variable name expected."); } break; case GS_CMD_addPositionVariableToPosition: if (stringData != NULL) { float tmpx, tmpy, tmpz; bool success = sp->getScript()->getGlobalPositionVariableValue(stringData, &tmpx, &tmpy, &tmpz); if (success) { gsd->position += VC3(tmpx, tmpy, tmpz); } else { sp->error("PositionScripting::process - addPositionVariableToPosition, failed to get position variable value (variable does not exist or type mismatch)."); sp->debug(stringData); } } else { sp->error("PositionScripting::process - addPositionVariableToPosition parameter missing, position variable name expected."); } break; case GS_CMD_setPositionKeepingHeight: { VC3 tmp(0,0,0); if (gs_coordinate_param(game->gameMap, stringData, &tmp)) { gsd->position.x = tmp.x; gsd->position.y = tmp.y; } else { sp->error("PositionScripting::process - Missing or bad setPositionKeepingHeight parameter."); } } break; case GS_CMD_setPositionXToFloat: { float floatData = *((float *)&intData); gsd->position.x = floatData; } break; case GS_CMD_setPositionZToFloat: { float floatData = *((float *)&intData); gsd->position.z = floatData; } break; case GS_CMD_rayTraceToSecondaryPosition: { VC3 middle_pos = (gsd->secondaryPosition + gsd->position) * 0.5f; VC3 dir = gsd->secondaryPosition - gsd->position; float length = dir.GetLength(); dir *= 1.0f / length; bool no_units = stringData && strstr(stringData, "no_units"); // disable collision for units if(no_units) { IUnitListIterator *iter = game->units->getNearbyAllUnits(middle_pos, length * length); while (iter->iterateAvailable()) { Unit *u = iter->iterateNext(); if(u && u->getVisualObject()) { u->getVisualObject()->setCollidable(false); } } delete iter; } // raycast *lastValue = 0; if(game && game->getGameScene()) { GameCollisionInfo cinfo; game->getGameScene()->rayTrace(gsd->position, dir, length, cinfo, true, false); if(cinfo.hit) { gsd->position = cinfo.position; *lastValue = 1; } } // re-enable collision for units if(no_units) { IUnitListIterator *iter = game->units->getNearbyAllUnits(middle_pos, length * length); while (iter->iterateAvailable()) { Unit *u = iter->iterateNext(); if(u && u->getVisualObject()) { u->getVisualObject()->setCollidable(true); } } delete iter; } } break; default: sp->error("PositionScripting::process - Unknown command."); assert(0); } }
void VisualEffect::init(IPointableObject *object, IPointableObject *origin, const VC3 &position, const VC3 &endPosition, const VC3 &rotation, int muzzleFlashBarrelNumber) { // make sure this is called only once. assert(visualObject == NULL); // set the object we want to follow... if (effectType->getFollow() == VisualEffectType::VISUALEFFECT_FOLLOW_NONE) { follow = NULL; } else { if (effectType->getFollow() == VisualEffectType::VISUALEFFECT_FOLLOW_OBJECT) { follow = object; } else { follow = origin; } } // visual object... visualObject = effectType->getNewVisualObject(); if (effectType->getType() == VisualEffectType::VISUALEFFECT_TYPE_MUZZLEFLASH) { // special case: muzzleflash if (visualObject != NULL && follow != NULL) { Muzzleflasher::createMuzzleflash(follow, visualObject, muzzleFlashBarrelNumber); visualObject->setInScene(false); } else { //Logger::getInstance()->error("VisualEffect::init - Null visualObject or follow unit for muzzleflash."); } this->position = position; return; } if (effectType->getType() == VisualEffectType::VISUALEFFECT_TYPE_EJECT) { this->position = position; return; } // normal and ray visualeffects... visualObject->setCollidable(false); visualObject->setInScene(true); // set position, rotation and scale based on type and the // given parameters... if (effectType->getType() == VisualEffectType::VISUALEFFECT_TYPE_NORMAL) { this->position = position; } if (effectType->getType() == VisualEffectType::VISUALEFFECT_TYPE_RAY) { this->position = (position + endPosition) / 2; VC3 diffVec = endPosition - position; float raylen = diffVec.GetLength(); VC3 scale(1,1,raylen); visualObject->setScale(scale); } if (effectType->getType() == VisualEffectType::VISUALEFFECT_TYPE_NORMAL) { this->position = position; } visualObject->setPosition(this->position); visualObject->setRotation(rotation.x, rotation.y, rotation.z); }
bool ReconChecker::isReconAvailableAtPosition(Game *game, int player, const VC3 &position) { LinkedList *ulist = game->units->getAllUnits(); LinkedListIterator iter = LinkedListIterator(ulist); while (iter.iterateAvailable()) { Unit *u = (Unit *)iter.iterateNext(); // unit is friendly towards player? // (but player does not need to be friendly towards the unit ;) if (u->isActive() && !u->isDestroyed() && !game->isHostile(u->getOwner(), player) && u->getReconValue() > 0 && u->getMoveState() != Unit::UNIT_MOVE_STATE_UNCONSCIOUS) { VC3 rayStartPosition = u->getPosition() + VC3(0, 2.0f, 0); VC3 target = position; float terrainHeight = game->gameMap->getScaledHeightAt(target.x, target.z); if (target.y < terrainHeight + 2.0f) target.y = terrainHeight + 2.0f; VC3 dir = target - rayStartPosition; float dirLen = dir.GetLength(); dir.Normalize(); if (dirLen > u->getUnitType()->getVisionRange() + 2.0f) { continue; } // TEMP! // ignore all small own units (1.5m)... // except the one we're trying to hit LinkedList *oul = game->units->getOwnedUnits(u->getOwner()); LinkedListIterator iter = LinkedListIterator(oul); while (iter.iterateAvailable()) { Unit *ou = (Unit *)iter.iterateNext(); if (ou != u && ou->getUnitType()->getSize() <= 1.5f) ou->getVisualObject()->setCollidable(false); } // disable collision check for this unit u->getVisualObject()->setCollidable(false); GameCollisionInfo cinfo; game->getGameScene()->rayTrace(rayStartPosition, dir, (float)dirLen, cinfo, false, true); // collision check back u->getVisualObject()->setCollidable(true); // TEMP! // restore them all... oul = game->units->getOwnedUnits(u->getOwner()); iter = LinkedListIterator(oul); while (iter.iterateAvailable()) { Unit *ou = (Unit *)iter.iterateNext(); if (ou != u && ou->getUnitType()->getSize() <= 1.5f) ou->getVisualObject()->setCollidable(true); } if (cinfo.hit) { // 4 meters max dist. if (cinfo.range >= dirLen - 4.0f) { return true; } } else { return true; } } } return false; }
void UnitFormation::addMovePoint(std::vector<Unit *> *units, const VC3 &scaledMapPos, Unit::MoveType moveType) { // If some units have waypoints set, they are overriden // If all units have same amount of waypoints, just add // -- Check if too far away from each other?? // Just override all move points (and target?) int i; VC3 avgPos = VC3(0,0,0); for (i = 0; i < (int)units->size(); i++) { Unit *u = (*units)[i]; avgPos += u->getPosition(); } avgPos /= (float)units->size(); // positions already taken by a unit // (so that others won't try to go there too) std::vector<std::pair<int, int> > pointsTaken; bool clickedBlocked = data->gameScene->isBlockedAtScaled( scaledMapPos.x, scaledMapPos.z, 0); IStorm3D_Model *buildingModel = NULL; ConnectionChecker *connectionChecker = NULL; if (units->size() > 1 || clickedBlocked) { int px = data->gameMap->scaledToPathfindX(scaledMapPos.x); int py = data->gameMap->scaledToPathfindY(scaledMapPos.z); buildingModel = data->gameScene->getBuildingModelAtPathfind(px, py); // HACK: // ok, did we click blocked and not inside building (building wall maybe)? // now check if there is a building nearby.. if (clickedBlocked && buildingModel == NULL) { px+=2; buildingModel = data->gameScene->getBuildingModelAtPathfind(px, py); px-=4; if (buildingModel == NULL && data->gameMap->inPathfindBoundaries(px, py)) { buildingModel = data->gameScene->getBuildingModelAtPathfind(px, py); } px+=2; py+=2; if (buildingModel == NULL && data->gameMap->inPathfindBoundaries(px, py)) { buildingModel = data->gameScene->getBuildingModelAtPathfind(px, py); } py-=4; if (buildingModel == NULL && data->gameMap->inPathfindBoundaries(px, py)) { buildingModel = data->gameScene->getBuildingModelAtPathfind(px, py); } } // smaller "rooms" inside buildings... int connDist = 14; if (buildingModel != NULL) connDist = 10; connectionChecker = new ConnectionChecker(data->gameScene, px, py, connDist); } for (i = 0; i < (int)units->size(); i++) { Unit *u = (*units)[i]; UnitActor *ua = getUnitActorForUnit(u); VC3 offset = u->getPosition() - avgPos; offset.y = 0; float offsetLen = offset.GetLength(); if (offsetLen > 0.01f) { offset.Normalize(); } float destX, okDestX; float destZ, okDestZ; //okDestX = scaledMapPos.x + offset.x; //okDestZ = scaledMapPos.z + offset.z; okDestX = scaledMapPos.x; okDestZ = scaledMapPos.z; float minDist = 0.5f; float maxDist = 3.0f; if (units->size() == 1) { minDist = 0; maxDist = 1.0f; } else { minDist += (float)units->size() * 0.2f; maxDist += (float)units->size() * 0.2f; } bool nonBlockedPassed = false; // first solve a position that would kinda match current position // in formation... (from formation center to some direction) for (float distfactor = minDist; distfactor <= maxDist; distfactor += 0.1f) { if (distfactor > offsetLen) break; destX = scaledMapPos.x + (offset.x * distfactor); destZ = scaledMapPos.z + (offset.z * distfactor); if (data->gameMap->isWellInScaledBoundaries(destX, destZ)) { int ox = data->gameMap->scaledToObstacleX(destX); int oy = data->gameMap->scaledToObstacleY(destZ); //if (data->gameMap->getObstacleHeight(ox, oy) == 0) if (!data->gameScene->isBlocked(ox, oy, 0)) { okDestX = destX; okDestZ = destZ; nonBlockedPassed = true; } else { if (nonBlockedPassed) { break; } } } } // then try to adjust position so that it would be nicely // covered from enemy... if (units->size() > 1 || clickedBlocked) { int ox = data->gameMap->scaledToObstacleX(okDestX); int oy = data->gameMap->scaledToObstacleY(okDestZ); /* if (connectionChecker != NULL) { delete connectionChecker; } connectionChecker = new ConnectionChecker(data->gameScene, ox, oy, 8); */ VC3 pos = u->getPosition(); int moveDirX = ox - data->gameMap->scaledToObstacleX(pos.x); int moveDirY = oy - data->gameMap->scaledToObstacleY(pos.z); int coverFromX = ox + moveDirX; int coverFromY = oy + moveDirY; if (u->targeting.hasTarget() && u->targeting.getTargetUnit() != NULL) { VC3 targPos = u->targeting.getTargetUnit()->getPosition(); coverFromX = data->gameMap->scaledToObstacleX(targPos.x); coverFromY = data->gameMap->scaledToObstacleY(targPos.z); } else { if (u->getSeeUnit() != NULL) { VC3 seePos = u->getSeeUnit()->getPosition(); coverFromX = data->gameMap->scaledToObstacleX(seePos.x); coverFromY = data->gameMap->scaledToObstacleY(seePos.z); } } int tx1 = ox - 8; int ty1 = oy - 8; int tx2 = ox + 8; int ty2 = oy + 8; if (tx1 < 0) tx1 = 0; if (ty1 < 0) ty1 = 0; if (tx2 >= data->gameMap->getObstacleSizeX()) tx2 = data->gameMap->getObstacleSizeX() - 1; if (ty2 >= data->gameMap->getObstacleSizeX()) ty2 = data->gameMap->getObstacleSizeY() - 1; int preferX = ox; int preferY = oy; int preferDistFactorSq = 9999*9999; for (int ty = ty1; ty <= ty2; ty++) { for (int tx = tx1; tx <= tx2; tx++) { int factSq; if (CoverFinder::isCoveredFrom(data->gameMap->getCoverMap(), tx, ty, coverFromX, coverFromY)) { factSq = (tx - ox)*(tx - ox) + (ty - oy)*(ty - oy); /* } else if (data->gameMap->getHideMap()->getHiddenessAt(tx, ty) == HideMap::maxHiddeness) { // hiddeness not quite as important as covered. factSq = 2*(tx - ox)*(tx - ox) + 2*(ty - oy)*(ty - oy); factSq += 3*3; */ } else { // no hiddeness, no cover, not preferred very much... factSq = 4*(tx - ox)*(tx - ox) + 4*(ty - oy)*(ty - oy); factSq += 6*6; } if (factSq < preferDistFactorSq) { // penalty for points are already taken by another unit int pointAmount = pointsTaken.size(); for (int i = 0; i < pointAmount; i++) { if (abs(pointsTaken[i].first - tx) <= 2 && abs(pointsTaken[i].second - ty) <= 2) { if (abs(pointsTaken[i].first - tx) <= 1 && abs(pointsTaken[i].second - ty) <= 1) { if (pointsTaken[i].first == tx && pointsTaken[i].second == ty) factSq += 6*6; else factSq += 4*4; } else { factSq += 2*2; } } } } // penalty if not in same building area if (factSq < preferDistFactorSq) { if (data->gameScene->getBuildingModelAtPathfind(tx, ty) != buildingModel) { factSq += 40*40; } } // penalty if not in the same "room" if (factSq < preferDistFactorSq) { if (!connectionChecker->isCenterConnectedTo(tx - ox, ty - oy)) { factSq += 30*30; } } // blocked really gets penalty :) if (data->gameScene->isBlockedAtScaled( data->gameMap->obstacleToScaledX(tx), data->gameMap->obstacleToScaledY(ty), 0)) { factSq += 100*100; } if (factSq < preferDistFactorSq) { preferDistFactorSq = factSq; preferX = tx; preferY = ty; } } } okDestX = data->gameMap->obstacleToScaledX(preferX); okDestZ = data->gameMap->obstacleToScaledY(preferY); pointsTaken.push_back(std::pair<int, int>(preferX, preferY)); } // now move right next to any obstacle... for (int i = 1; i < 10; i++) { // right? { float adjustedX = okDestX + ((float)i / 10.0f); float adjustedZ = okDestZ; int ox = data->gameMap->scaledToObstacleX(adjustedX); int oy = data->gameMap->scaledToObstacleY(adjustedZ); //if (data->gameMap->getObstacleHeight(ox, oy) != 0) if (data->gameScene->isBlocked(ox, oy, 0)) { okDestX = adjustedX - 0.10f; break; } } // left? { float adjustedX = okDestX - ((float)i / 10.0f); float adjustedZ = okDestZ; int ox = data->gameMap->scaledToObstacleX(adjustedX); int oy = data->gameMap->scaledToObstacleY(adjustedZ); //if (data->gameMap->getObstacleHeight(ox, oy) != 0) if (data->gameScene->isBlocked(ox, oy, 0)) { okDestX = adjustedX + 0.10f; break; } } // up? { float adjustedX = okDestX; float adjustedZ = okDestZ - ((float)i / 10.0f); int ox = data->gameMap->scaledToObstacleX(adjustedX); int oy = data->gameMap->scaledToObstacleY(adjustedZ); //if (data->gameMap->getObstacleHeight(ox, oy) != 0) if (data->gameScene->isBlocked(ox, oy, 0)) { okDestZ = adjustedZ + 0.10f; break; } } // down? { float adjustedX = okDestX; float adjustedZ = okDestZ + ((float)i / 10.0f); int ox = data->gameMap->scaledToObstacleX(adjustedX); int oy = data->gameMap->scaledToObstacleY(adjustedZ); //if (data->gameMap->getObstacleHeight(ox, oy) != 0) if (data->gameScene->isBlocked(ox, oy, 0)) { okDestZ = adjustedZ - 0.10f; break; } } } // now go to destination... ua->setPathTo(u, VC3(okDestX, 0, okDestZ)); // and set unit behaviour modes... if (moveType == Unit::MoveTypeNormal) { u->setStealthing(false); u->setSpeed(Unit::UNIT_SPEED_FAST); u->setMode(Unit::UNIT_MODE_DEFENSIVE); } if (moveType == Unit::MoveTypeFast) { u->setStealthing(false); if (u->getRunningValue() > 0) { u->setSpeed(Unit::UNIT_SPEED_SPRINT); u->setMode(Unit::UNIT_MODE_HOLD_FIRE); } else { // unit incapable of sprinting, just move at normal running speed. u->setSpeed(Unit::UNIT_SPEED_FAST); u->setMode(Unit::UNIT_MODE_HOLD_FIRE); } } if (moveType == Unit::MoveTypeStealth) { // stealth armor goes to stealth mode... if (u->getStealthValue() > 0) { u->setSpeed(Unit::UNIT_SPEED_FAST); u->setStealthing(true); u->setMode(Unit::UNIT_MODE_HOLD_FIRE); } else { // other just normal movement (no more sneak) //u->setSpeed(Unit::UNIT_SPEED_SLOW); u->setSpeed(Unit::UNIT_SPEED_FAST); u->setStealthing(false); u->setMode(Unit::UNIT_MODE_DEFENSIVE); } } } if (connectionChecker != NULL) { delete connectionChecker; } }
void ParticleArea::biasValues(const VC3 &position, VC3 &velocity) const { float wx = position.x; float wy = position.z; if(gameMap->isWellInScaledBoundaries(wx, wy)) { float height = position.y / gameMap->getScaleHeight(); int x = gameMap->scaledToObstacleX(wx); int y = gameMap->scaledToObstacleY(wy); CoverMap *coverMap = gameMap->getCoverMap(); CoverMap::COVER_DIRECTION dir = coverMap->getNearestCoverDirection(x, y); int distance = coverMap->getDistanceToNearestCover(x, y); { AreaMap *areaMap = gameMap->getAreaMap(); int ax = x; int ay = y; if(dir == CoverMap::COVER_DIRECTION_N) ay -= distance; else if(dir == CoverMap::COVER_DIRECTION_NE) { int df = int(distance * 0.7071f); ax += df; ay -= df; } else if(dir == CoverMap::COVER_DIRECTION_E) ax += distance; else if(dir == CoverMap::COVER_DIRECTION_SE) { int df = int(distance * 0.7071f); ax += df; ay += df; } else if(dir == CoverMap::COVER_DIRECTION_S) ay += distance; else if(dir == CoverMap::COVER_DIRECTION_SW) { int df = int(distance * 0.7071f); ax -= df; ay += df; } else if(dir == CoverMap::COVER_DIRECTION_W) ax -= distance; else if(dir == CoverMap::COVER_DIRECTION_NW) { int df = int(distance * 0.7071f); ax -= df; ay -= df; } if(areaMap->isAreaAnyValue(ax, ay, AREAMASK_OBSTACLE_UNHITTABLE) || gameMap->getObstacleHeight(ax, ay) < 20) return; } if(distance > 0 && distance < 8) { float blendFactor = 1.f - (distance / 8.f); blendFactor *= 0.04f; float angle = ((dir - 1) * 45.f) * PI / 180.f; VC3 blendVector; blendVector.x = -sinf(angle); blendVector.z = cosf(angle); blendVector *= velocity.GetLength(); blendVector *= blendFactor; velocity *= 1.f - blendFactor; velocity += blendVector; } } }
// return true if position ok and decal should be added // false, if position NOT ok and decal should NOT be added bool DecalPositionCalculator::calculateDecalPosition( game::GameScene *gameScene, const VC3 &origin, const VC3 &velocity, DECAL_POSITIONING positioning, int positionRandom, VC3 *resultPosition, QUAT *resultRotation) { assert(positioning != DecalPositionCalculator::DECAL_POSITIONING_INVALID); game::GameMap *gameMap = gameScene->getGameMap(); bool hitWall = false; *resultPosition = origin; *resultRotation = QUAT((-3.1415926f / 2.0f),0,0); // if velocity positioning... if (positioning == DecalPositionCalculator::DECAL_POSITIONING_VELOCITY) { VC3 velocityRandomized; if (positionRandom > 0) { velocityRandomized = velocity * GAME_TICKS_PER_SECOND; // TEMP //char buf[64]; //sprintf(buf, "%f,%f,%f", velocity.x, velocity.y, velocity.z); //Logger::getInstance()->error(buf); // TODO: add positionRandom to velocity _angle_... // (or maybe just do a quick hack and add it to xz-coordinates?) velocityRandomized.x += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; velocityRandomized.z += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; // add to y too? maybe should add downward only? // NOTE: biased downward velocityRandomized.y += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; velocityRandomized.y -= float(positionRandom) / 100.0f * 0.5f; } else { velocityRandomized = velocity; } velocityRandomized *= 2.0f; IStorm3D_Scene *scene = gameScene->getStormScene(); VC3 dir = velocityRandomized.GetNormalized(); VC3 rayOrigin = origin; float rayLen = velocityRandomized.GetLength(); Storm3D_CollisionInfo sceneColl; sceneColl.includeTerrainObjects = false; scene->RayTrace(rayOrigin, dir, rayLen, sceneColl, true); /* if (sceneColl.hit) { VC3 hitNormal = sceneColl.plane_normal; // make a "wall" hit if normal-y is not nearly 1 //if (fabs(hitNormal.y) < 0.8f) { hitWall = true; VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f); x.Normalize(); x -= hitNormal * x.GetDotWith(hitNormal); VC3 y = -x.GetCrossWith(hitNormal); assert(fabsf(x.GetDotWith(y)) < 0.0001f); assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f); MAT tm; tm.Set(0, x.x); tm.Set(1, x.y); tm.Set(2, x.z); tm.Set(4, y.x); tm.Set(5, y.y); tm.Set(6, y.z); tm.Set(8, hitNormal.x); tm.Set(9, hitNormal.y); tm.Set(10, hitNormal.z); *resultRotation = tm.GetRotation(); } *resultPosition = sceneColl.position; } else { *resultPosition += velocityRandomized; } */ // New version { VC3 hitNormal(0, 1.f, 0); if(sceneColl.hit) { hitNormal = sceneColl.plane_normal; *resultPosition = sceneColl.position; } else { *resultPosition += velocityRandomized; VC2 p2(resultPosition->x, resultPosition->z); hitNormal = gameScene->getTerrain()->getFaceNormal(p2); } { if(sceneColl.hit) hitWall = true; /* VC3 y = dir; VC3 z = hitNormal; y -= hitNormal * y.GetDotWith(hitNormal); VC3 x = z.GetCrossWith(y); */ VC3 x = dir; x.y = 0.f; x.Normalize(); x -= hitNormal * x.GetDotWith(hitNormal); VC3 y = -x.GetCrossWith(hitNormal); VC3 z = hitNormal; MAT tm; tm.Set(0, x.x); tm.Set(1, x.y); tm.Set(2, x.z); tm.Set(4, y.x); tm.Set(5, y.y); tm.Set(6, y.z); tm.Set(8, z.x); tm.Set(9, z.y); tm.Set(10, z.z); resultRotation->MakeFromAngles(0.f, 0.f, -PI*0.5f); *resultRotation = (*resultRotation) * tm.GetRotation(); /* VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f); x.Normalize(); x -= hitNormal * x.GetDotWith(hitNormal); VC3 y = -x.GetCrossWith(hitNormal); assert(fabsf(x.GetDotWith(y)) < 0.0001f); assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f); MAT tm; tm.Set(0, x.x); tm.Set(1, x.y); tm.Set(2, x.z); tm.Set(4, y.x); tm.Set(5, y.y); tm.Set(6, y.z); tm.Set(8, hitNormal.x); tm.Set(9, hitNormal.y); tm.Set(10, hitNormal.z); *resultRotation = tm.GetRotation(); */ } } // TODO: some kind of terrain raytrace maybe...? // should collide to walls, etc. } // if downward positioning... if (positioning == DecalPositionCalculator::DECAL_POSITIONING_DOWNWARD) { if (positionRandom > 0) { // TODO: add a random xz-offset to result position //*resultPosition += randomizedOffset; resultPosition->x += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; resultPosition->z += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; } /* // psd { VC2 p2(resultPosition->x, resultPosition->z); VC3 hitNormal = gameScene->getTerrain()->getFaceNormal(p2); VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f); x.Normalize(); x -= hitNormal * x.GetDotWith(hitNormal); VC3 y = -x.GetCrossWith(hitNormal); assert(fabsf(x.GetDotWith(y)) < 0.0001f); assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f); MAT tm; tm.Set(0, x.x); tm.Set(1, x.y); tm.Set(2, x.z); tm.Set(4, y.x); tm.Set(5, y.y); tm.Set(6, y.z); tm.Set(8, hitNormal.x); tm.Set(9, hitNormal.y); tm.Set(10, hitNormal.z); *resultRotation = tm.GetRotation(); } */ VC3 fooNormal; calculateDecalRotation(gameScene, *resultPosition, *resultRotation, 0.f, fooNormal); } // now check that we're still inside map boundaries if (!gameMap->isWellInScaledBoundaries(resultPosition->x, resultPosition->z)) { // out of map. return false; } // then fix decal height to ground height if (positioning == DecalPositionCalculator::DECAL_POSITIONING_DOWNWARD || positioning == DecalPositionCalculator::DECAL_POSITIONING_VELOCITY) { if (!hitWall) { resultPosition->y = gameMap->getScaledHeightAt(resultPosition->x, resultPosition->z); } } // check that not on top of metal grid area... if (game::MaterialManager::isMaterialUnderPosition(gameMap, *resultPosition, MATERIAL_METAL_GRATE)) { // on top of grid, no decal here. return false; } // TODO: check that not inside a wall, terrainobject, etc. // if so, return false return true; }