/** * calculateTrajectory. * @return true when a trajectory is possible. */ bool Projectile::calculateTrajectory(double accuracy) { Position originVoxel, targetVoxel; int direction; int dirYshift[8] = {1, 1, 8, 15, 15, 15, 8, 1 }; int dirXshift[8] = {8, 14, 15, 15, 8, 1, 1, 1 }; // large units : x2 originVoxel = Position(_origin.x*16, _origin.y*16, _origin.z*24); originVoxel.z += -_save->getTile(_origin)->getTerrainLevel(); BattleUnit *bu = _save->getTile(_origin)->getUnit(); originVoxel.z += bu->isKneeled()?bu->getUnit()->getKneelHeight():bu->getUnit()->getStandHeight(); originVoxel.z -= 3; if (originVoxel.z >= (_origin.z + 1)*24) { _origin.z++; } direction = bu->getDirection(); originVoxel.x += dirXshift[direction]; originVoxel.y += 15-dirYshift[direction]; // determine the target voxel. // aim at the center of the unit, the object, the walls or the floor (in that priority) // if there is no LOF to the center, try elsewhere (more outward). // Store this target voxel. Tile *tile = _save->getTile(_target); if (tile->getUnit() != 0) { if (_origin == _target) { targetVoxel = Position(_target.x*16 + 8, _target.y*16 + 8, _target.z*24); } else { targetVoxel = Position(_target.x*16 + 8, _target.y*16 + 8, _target.z*24 + tile->getUnit()->getUnit()->getStandHeight()/2); } } else if (tile->getMapData(O_OBJECT) != 0) { targetVoxel = Position(_target.x*16 + 8, _target.y*16 + 8, _target.z*24 + 10); } else if (tile->getMapData(O_NORTHWALL) != 0) { targetVoxel = Position(_target.x*16 + 8, _target.y*16 + 16, _target.z*24 + 10); } else if (tile->getMapData(O_WESTWALL) != 0) { targetVoxel = Position(_target.x*16, _target.y*16 + 8, _target.z*24 + 10); } else if (tile->getMapData(O_FLOOR) != 0) { targetVoxel = Position(_target.x*16 + 8, _target.y*16 + 8, _target.z*24); } else { return false; // no line of fire } // apply some accuracy modifiers (todo: calculate this) // This will results in a new target voxel applyAccuracy(originVoxel, &targetVoxel, accuracy); // finally do a line calculation and store this trajectory. _save->getTerrainModifier()->calculateLine(originVoxel, targetVoxel, true, &_trajectory, bu); return true; }
/** * Initializes the explosion. * The animation and sound starts here. * If the animation is finished, the actual effect takes place. */ void ExplosionBState::init() { if (_item) { _power = _item->getRules()->getPower(); // this usually only applies to melee, but as a concession for modders i'll leave it here in case they wanna make bows or something. if (_item->getRules()->isStrengthApplied() && _unit) { _power += _unit->getBaseStats()->strength; } _areaOfEffect = _item->getRules()->getBattleType() != BT_MELEE && _item->getRules()->getExplosionRadius() != 0 && !_cosmetic; } else if (_tile) { _power = _tile->getExplosive(); _areaOfEffect = true; } else if (_unit && (_unit->getSpecialAbility() == SPECAB_EXPLODEONDEATH || _unit->getSpecialAbility() == SPECAB_BURN_AND_EXPLODE)) { _power = _parent->getMod()->getItem(_unit->getArmor()->getCorpseGeoscape())->getPower(); _areaOfEffect = true; } else { _power = 120; _areaOfEffect = true; } Tile *t = _parent->getSave()->getTile(Position(_center.x/16, _center.y/16, _center.z/24)); if (_areaOfEffect) { if (_power) { int frame = Mod::EXPLOSION_OFFSET; if (_item) { frame = _item->getRules()->getHitAnimation(); } if (_parent->getDepth() > 0) { frame -= Explosion::EXPLODE_FRAMES; } int frameDelay = 0; int counter = std::max(1, (_power/5) / 5); _parent->getMap()->setBlastFlash(true); for (int i = 0; i < _power/5; i++) { int X = RNG::generate(-_power/2,_power/2); int Y = RNG::generate(-_power/2,_power/2); Position p = _center; p.x += X; p.y += Y; Explosion *explosion = new Explosion(p, frame, frameDelay, true); // add the explosion on the map _parent->getMap()->getExplosions()->push_back(explosion); if (i > 0 && i % counter == 0) { frameDelay++; } } _parent->setStateInterval(BattlescapeState::DEFAULT_ANIM_SPEED/2); // explosion sound if (_power <= 80) _parent->getMod()->getSoundByDepth(_parent->getDepth(), Mod::SMALL_EXPLOSION)->play(); else _parent->getMod()->getSoundByDepth(_parent->getDepth(), Mod::LARGE_EXPLOSION)->play(); _parent->getMap()->getCamera()->centerOnPosition(t->getPosition(), false); } else { _parent->popState(); } } else // create a bullet hit { _parent->setStateInterval(std::max(1, ((BattlescapeState::DEFAULT_ANIM_SPEED/2) - (10 * _item->getRules()->getExplosionSpeed())))); int anim = _item->getRules()->getHitAnimation(); int sound = _item->getRules()->getHitSound(); if (_cosmetic) // Play melee animation on hitting and psiing { anim = _item->getRules()->getMeleeAnimation(); } if (anim != -1) { Explosion *explosion = new Explosion(_center, anim, 0, false, _cosmetic); _parent->getMap()->getExplosions()->push_back(explosion); } _parent->getMap()->getCamera()->setViewLevel(_center.z / 24); BattleUnit *target = t->getUnit(); if (_cosmetic && _parent->getSave()->getSide() == FACTION_HOSTILE && target && target->getFaction() == FACTION_PLAYER) { _parent->getMap()->getCamera()->centerOnPosition(t->getPosition(), false); } if (sound != -1 && !_cosmetic) { // bullet hit sound _parent->getMod()->getSoundByDepth(_parent->getDepth(), sound)->play(-1, _parent->getMap()->getSoundAngle(_center / Position(16,16,24))); } } }
/** * Check if a Tile at position (row,col) has a widget. * @param row :: The row to check. * @param col :: The column to check. */ bool TiledWindow::hasWidget(int row, int col) const { Tile *tile = getTile(row, col); return tile->widget() != NULL; }
QVector<QVector<Tile>> Maze::setTileDistances(QVector<QVector<Tile>> maze) { // TODO: MACK - dedup some of this with hasNoInaccessibleLocations // The maze is guarenteed to be nonempty and rectangular int width = maze.size(); int height = maze.at(0).size(); // Helper lambda for retrieving and adjacent tile if one exists, nullptr if not // TODO: MACK - this should be in maze utilities too auto getNeighbor = [&maze, &width, &height](int x, int y, Direction direction) { switch (direction) { case Direction::NORTH: return (y < height - 1 ? &maze[x][y + 1] : nullptr); case Direction::EAST: return (x < width - 1 ? &maze[x + 1][y] : nullptr); case Direction::SOUTH: return (0 < y ? &maze[x][y - 1] : nullptr); case Direction::WEST: return (0 < x ? &maze[x - 1][y] : nullptr); } }; // Determine all of the center tiles // TODO: MACK - use the maze checker function for this QVector<Tile*> centerTiles; centerTiles.push_back(&maze[(width - 1) / 2][(height - 1) / 2]); if (width % 2 == 0) { centerTiles.push_back(&maze[ width / 2][(height - 1) / 2]); if (height % 2 == 0) { centerTiles.push_back(&maze[(width - 1) / 2][ height / 2]); centerTiles.push_back(&maze[ width / 2][ height / 2]); } } else if (height % 2 == 0) { centerTiles.push_back(&maze[(width - 1) / 2][ height / 2]); } // The queue for the BFS QQueue<Tile*> discovered; // Set the distances of the center tiles and push them to the queue for (Tile* tile : centerTiles) { tile->setDistance(0); discovered.enqueue(tile); } // Now do a BFS while (!discovered.empty()){ Tile* tile = discovered.dequeue(); for (Direction direction : DIRECTIONS) { if (!tile->isWall(direction)) { Tile* neighbor = getNeighbor(tile->getX(), tile->getY(), direction); if (neighbor != nullptr && neighbor->getDistance() == -1) { neighbor->setDistance(tile->getDistance() + 1); discovered.enqueue(neighbor); } } } } return maze; }
bool WeaponDistance::useWeapon(Player* player, Item* item, Creature* target) const { int32_t damageModifier = playerWeaponCheck(player, target); if (damageModifier == 0) { return false; } int32_t chance; if (hitChance == 0) { //hit chance is based on distance to target and distance skill uint32_t skill = player->getSkill(SKILL_DIST, SKILL_LEVEL); const Position& playerPos = player->getPosition(); const Position& targetPos = target->getPosition(); uint32_t distance = std::max<uint32_t>(Position::getDistanceX(playerPos, targetPos), Position::getDistanceY(playerPos, targetPos)); if (maxHitChance == 75) { //chance for one-handed weapons switch (distance) { case 1: chance = std::min<uint32_t>(skill, 74) + 1; break; case 2: chance = (uint32_t)((float)2.4 * std::min<uint32_t>(skill, 28)) + 8; break; case 3: chance = (uint32_t)((float)1.55 * std::min<uint32_t>(skill, 45)) + 6; break; case 4: chance = (uint32_t)((float)1.25 * std::min<uint32_t>(skill, 58)) + 3; break; case 5: chance = (uint32_t)((float)std::min<uint32_t>(skill, 74)) + 1; break; case 6: chance = (uint32_t)((float)0.8 * std::min<uint32_t>(skill, 90)) + 3; break; case 7: chance = (uint32_t)((float)0.7 * std::min<uint32_t>(skill, 104)) + 2; break; default: chance = hitChance; break; } } else if (maxHitChance == 90) { //formula for two-handed weapons switch (distance) { case 1: chance = (uint32_t)((float)1.2 * std::min<uint32_t>(skill, 74)) + 1; break; case 2: chance = (uint32_t)((float)3.2 * std::min<uint32_t>(skill, 28)); break; case 3: chance = (uint32_t)((float)2.0 * std::min<uint32_t>(skill, 45)); break; case 4: chance = (uint32_t)((float)1.55 * std::min<uint32_t>(skill, 58)); break; case 5: chance = (uint32_t)((float)1.2 * std::min<uint32_t>(skill, 74)) + 1; break; case 6: chance = (uint32_t)((float)1.0 * std::min<uint32_t>(skill, 90)); break; case 7: chance = (uint32_t)((float)1.0 * std::min<uint32_t>(skill, 90)); break; default: chance = hitChance; break; } } else if (maxHitChance == 100) { switch (distance) { case 1: chance = (uint32_t)((float)1.35 * std::min<uint32_t>(skill, 73)) + 1; break; case 2: chance = (uint32_t)((float)3.2 * std::min<uint32_t>(skill, 30)) + 4; break; case 3: chance = (uint32_t)((float)2.05 * std::min<uint32_t>(skill, 48)) + 2; break; case 4: chance = (uint32_t)((float)1.5 * std::min<uint32_t>(skill, 65)) + 2; break; case 5: chance = (uint32_t)((float)1.35 * std::min<uint32_t>(skill, 73)) + 1; break; case 6: chance = (uint32_t)((float)1.2 * std::min<uint32_t>(skill, 87)) - 4; break; case 7: chance = (uint32_t)((float)1.1 * std::min<uint32_t>(skill, 90)) + 1; break; default: chance = hitChance; break; } } else { chance = maxHitChance; } } else { chance = hitChance; } if (item->getWeaponType() == WEAPON_AMMO) { Item* bow = player->getWeapon(true); if (bow && bow->getHitChance() != 0) { chance += bow->getHitChance(); } } if (chance >= random_range(1, 100)) { if (elementDamage != 0) { int32_t damage = getElementDamage(player, target, item); CombatParams eParams; eParams.combatType = elementType; eParams.isAggressive = true; eParams.useCharges = true; Combat::doCombatHealth(player, target, damage, damage, eParams); } Weapon::internalUseWeapon(player, item, target, damageModifier); } else { //miss target Tile* destTile = target->getTile(); if (!Position::areInRange<1, 1, 0>(player->getPosition(), target->getPosition())) { std::vector<std::pair<int32_t, int32_t>> destList; destList.push_back(std::make_pair(-1, -1)); destList.push_back(std::make_pair(-1, 0)); destList.push_back(std::make_pair(-1, 1)); destList.push_back(std::make_pair(0, -1)); destList.push_back(std::make_pair(0, 0)); destList.push_back(std::make_pair(0, 1)); destList.push_back(std::make_pair(1, -1)); destList.push_back(std::make_pair(1, 0)); destList.push_back(std::make_pair(1, 1)); std::random_shuffle(destList.begin(), destList.end()); Position destPos = target->getPosition(); for (const auto& dir : destList) { Tile* tmpTile = g_game.getTile(destPos.x + dir.first, destPos.y + dir.second, destPos.z); // Blocking tiles or tiles without ground ain't valid targets for spears if (tmpTile && !tmpTile->hasProperty(IMMOVABLEBLOCKSOLID) && tmpTile->ground != NULL) { destTile = tmpTile; break; } } } Weapon::internalUseWeapon(player, item, destTile); } return true; }
void Player::update(double aDelta) { std::string ammoCount = ""; std::stringstream ammoAmount; ammoAmount << m_Ammo; ammoAmount >> ammoCount; m_Font->setText(ammoCount.c_str()); //update the projectile for(int i = 0; i < m_Projectiles.size(); i++) { if(m_Projectiles.at(i)->getIsActive() == true) { m_Projectiles.at(i)->update(aDelta); } } //Tower1 for(int i = 0; i < m_Level->getNumberOfTiles(); i++) { if(m_Level->getTileTypeForIndex(i) == TileTypeTower) { TowerTile* temp = (TowerTile*) m_Level->getTileForIndex(i); for(int location = 0; location < temp->getProjecticle().size(); location++) { if (temp->getProjecticle().at(location)->getIsActive()) temp->getProjecticle().at(location)->update(aDelta); } } } //remove aby inactive projectiles from the projectiles vectors int index = 0; while(index != m_Projectiles.size()) { if(m_Projectiles.at(index)->getIsActive() == false) { //delete the projectile and remove it from the vector delete m_Projectiles.at(index); m_Projectiles.erase(m_Projectiles.begin() + index); } else { index++; } } if (m_PathFinder->isSearchingPath() == true) { m_PathFinder->update(aDelta); } if (isAnimating() && m_AnimationPathNodeIndex > -1) { PathNode* pathNode = m_PathFinder->getPathNodeAtIndex(m_AnimationPathNodeIndex); Tile* tile = pathNode != NULL ? pathNode->getTile() : NULL; if(tile) { float centerX = tile->getX() + (tile->getWidth() - getWidth()) / 2.0f; float centerY = tile->getY() + (tile->getHeight() - getHeight()) / 2.0f; Tile * playerTile = m_Level->getTileForPosition(getX(), getY()); float speed = playerTile->getTileSpeed(); float playerX = animate(getX(), centerX, aDelta, speed); float playerY = animate(getY(), centerY, aDelta, speed); setPosition(playerX, playerY); //change G as float for slower and faster tiles if (playerX == centerX && playerY == centerY) { m_AnimationPathNodeIndex++; m_CurrentTile->setIsPath(false); setCurrentTile(tile); if (m_AnimationPathNodeIndex >= m_PathFinder->getPathSize()) { stopAnimating(); m_CurrentTile->setIsPath(false); } if(m_AbortAnimation) { m_AbortAnimation = false; findPath(); } } else { if(m_AbortAnimation == true) { m_AbortAnimation =false; findPath(); } } } } }
bool MainView::mouseReleased(u16 x, u16 y, MouseButton b) { //gvm->push(new Blink(1000, Gfx::color(0, 0, 255), {0,0,320,200}, 220)); /*gvm->cityView()->setCity(g->getCities().front());*/ //gvm->switchView(VIEW_ITEM_CRAFT); Position pos = Viewport::hoveredPosition(g->world, player, x, y); Tile* t = g->world->get(pos); if (t) { pos = t->position; City* c = t->city; Army* a = t->army; if (b == BUTTON_RIGHT) { if (a) { bool couldBeSelected = (!c || (c && !a->isPatrolling())); if (couldBeSelected && a->getOwner() == player) { switchToUnitSelection(a); return true; } else if (a->getOwner() != player) { gvm->armyView()->open(a); return true; } } if (c) { if (!c->isOutpost()) { gvm->cityView()->setCity(c); gvm->switchView(VIEW_CITY); } else { gvm->outpostView()->setCity(c); gvm->switchOverview(VIEW_OUTPOST); } player->resetArmy(); switchToNormalState(); } else { s16 upperBoundY = pos.y - Viewport::viewportH/2; s16 lowerBoundY = pos.y + (Viewport::viewportH - Viewport::viewportH/2); s16 ty = pos.y; if (upperBoundY < 0) ty = Viewport::viewportH/2; else if (lowerBoundY >= g->world->h) ty = g->world->h - (Viewport::viewportH - Viewport::viewportH/2); player->setViewport(pos.x, ty); } } else if (b == BUTTON_LEFT) { if (substate == SPELL_CAST && player->getSpellTarget() == Target::MAP_TILE) g->castSpell(t, player); else if (substate == SPELL_CAST && player->getSpellTarget() == Target::FRIENDLY_UNIT) { if (t->army && t->army->getOwner() == player) { // TODO: check if unit is just 1 directly cast? gvm->armyView()->setArmy(t->army); gvm->armyView()->setAcceptSpellTarget(); gvm->switchOverview(VIEW_ARMY); } } else if (substate == SPELL_CAST && player->getSpellTarget() == Target::FRIENDLY_CITY) { if (t->city && t->city->getOwner() == player) g->castSpell(t->city, player); } else { const unit_list& selectedUnits = player->getSelectedUnits();; const auto& route = player->getRoute(); const bool hasSelectedUnits = !selectedUnits.empty(); if (hasSelectedUnits && !route) player->computeRoute(t->position); else if (hasSelectedUnits && !route->completed() && route->dx() == t->x() && route->dy() == t->y() && player->selectedAvailMoves() > 0) { player->consumeRoute(); //player->push(new anims::UnitMovement(player, army, army->getRoute()->pendingPositions())); updateBuildButton(); } else if (hasSelectedUnits) player->computeRoute(t->position); /*if (route != null && !route.completed()) System.out.println(cx+" "+cy+" "+route.dx()+" "+route.dy());*/ } } } else { Army* army = player->getSelectedArmy(); if (army) { for (int j = 0; j < army->size(); ++j) { int xx = (246+23*(j%3)), yy = (78+29*(j/3)); if (x >= xx+2 && x <= xx+20+2 && y >= yy+2 && y <= yy+18+2) { // select/deselect unit in army if (b == BUTTON_LEFT) { Unit* unit = army->get(j); if (army->size() > 2 && player->isSelectedUnit(unit) && std::all_of(army->begin(), army->end(), [this](Unit* u) { return player->isSelectedUnit(u); })) { for (Unit* aunit : *army) if (aunit != unit) player->deselectUnit(aunit); } else { if (player->isSelectedUnit(unit)) player->deselectUnit(unit); else player->selectUnit(unit); } updateBuildButton(); army->clearRoute(); } // open detail view on unit else if (b == BUTTON_RIGHT) { gvm->unitDetailView()->setUnit(army->get(j)); gvm->switchOverview(VIEW_UNIT); } } } } } return true; }
bool SceneMgr::save(xs::DataChunk* pDataChunk,bool writeOccupants) { int nGridWidth = GRID_WIDTH; int nGridHeight = GRID_HEIGHT; if(!isValid()) { return false; } int nGridRow = Ceil(m_nMapHeight, nGridHeight); int nGridCol = Ceil(m_nMapWidth, nGridWidth); uint *pOffsetsData = 0; xs::Stream *pDataStream = 0; // 地图版本信息; pDataChunk->beginChunk('MVER',&pDataStream); m_nMapVersion = SUPPORT_EFFECT_SCALE_AND_ANGLE_ADJUST_MAP_VERSION; pDataStream->write(&m_nMapVersion, sizeof(m_nMapVersion)); pDataChunk->endChunk(); pDataChunk->beginChunk('MINF',&pDataStream); pDataStream->write(&m_nMapWidth,sizeof(m_nMapWidth)); pDataStream->write(&m_nMapHeight,sizeof(m_nMapHeight)); pDataChunk->endChunk(); xs::DataChunk::stChunk *pIdxChunk = pDataChunk->beginChunk('MIDX',&pDataStream); for(int row = 0;row < nGridRow;row++) for(int col = 0;col < nGridCol;col++) { uint offset = 0; pDataStream->write(&offset,sizeof(offset)); } pDataChunk->endChunk(); pOffsetsData = (uint*)pIdxChunk->m_pData; m_bWriteOccupants = writeOccupants; int nTileRow = nGridHeight / 32; int nTileCol = nGridWidth / (64 / 2); xs::Point ptTileLeftTop; xs::Point ptLeftTop; for(int row = 0;row < nGridRow;row++) for(int col = 0;col < nGridCol;col++) { pDataChunk->beginChunk('MDAT',&pDataStream); pOffsetsData[row * nGridCol + col] = pDataChunk->getOffset(); ptLeftTop.x = col * nGridWidth; ptLeftTop.y = row * nGridHeight; m_SceneCo.pixel2Tile(ptLeftTop, ptTileLeftTop); _SaveBlock(pDataStream,ptTileLeftTop,nTileRow,nTileCol); pDataChunk->endChunk(); } m_bWriteOccupants = false; m_pGround->save(pDataChunk); SceneBlock mb; int nTileWidth = m_SceneCo.getMatrixWidth(); int nTileHeight = m_SceneCo.getMatrixHeight(); mb.SetMapSize(nTileWidth, nTileHeight); for (int row = 0; row < nTileHeight; ++row) { for (int col = 0; col < nTileWidth; ++col) { xs::Point ptTile (col, row); Tile *pTile = &getTile(ptTile); if (!pTile->isValid()) { mb.SetBlock(col, row, true); } else { mb.SetBlock(col, row, pTile->isBlock() ? true: false); } } } pDataChunk->beginChunk('MWPT',&pDataStream); mb.Save(pDataStream); pDataChunk->endChunk(); return true; }
/** * Get's the TU cost to move from 1 tile to the other(ONE STEP ONLY). But also updates the endPosition, because it is possible * the unit goes upstairs or falls down while walking. * @param startPosition * @param direction * @param endPosition pointer * @param unit * @return TU cost - 255 if movement impossible */ int Pathfinding::getTUCost(const Position &startPosition, int direction, Position *endPosition, BattleUnit *unit) { _unit = unit; directionToVector(direction, endPosition); *endPosition += startPosition; bool fellDown = false; bool triedStairs = false; int size = _unit->getUnit()->getArmor()->getSize() - 1; int cost = 0; for (int x = size; x >= 0; x--) { for (int y = size; y >= 0; y--) { Tile *startTile = _save->getTile(startPosition + Position(x,y,0)); Tile *destinationTile = _save->getTile(*endPosition + Position(x,y,0)); cost = 0; // this means the destination is probably outside the map if (!destinationTile) return 255; // check if the destination tile can be walked over if (isBlocked(destinationTile, MapData::O_FLOOR) || isBlocked(destinationTile, MapData::O_OBJECT)) return 255; if (direction < DIR_UP) { // check if we can go this way if (isBlocked(startTile, destinationTile, direction)) return 255; if (startTile->getTerrainLevel() - destinationTile->getTerrainLevel() > 8 && x==0 && y==0) return 255; } else { // check if we can go up or down through gravlift or fly if (validateUpDown(unit, startPosition, direction)) { cost += 4; // vertical movement } else { return 255; } } // if we are on a stairs try to go up a level if (startTile->getTerrainLevel() < -12 && x==0 && y==0) { endPosition->z++; destinationTile = _save->getTile(*endPosition); triedStairs = true; } // this means the destination is probably outside the map if (!destinationTile) return 255; // check if we have floor, else fall down while (canFallDown(destinationTile) && (_movementType != MT_FLY || triedStairs) && x==0 && y==0) { endPosition->z--; destinationTile = _save->getTile(*endPosition); fellDown = true; } // if we don't want to fall down and there is no floor, it ends here if (!fellDown && destinationTile->hasNoFloor() && x==0 && y==0) { if (_movementType != MT_FLY) return 255; else cost = 4; } // check if the destination tile can be walked over if ((isBlocked(destinationTile, MapData::O_FLOOR) || isBlocked(destinationTile, MapData::O_OBJECT)) && !fellDown) { return 255; } // calculate the cost by adding floor walk cost and object walk cost cost += destinationTile->getTUCost(MapData::O_FLOOR, _movementType); if (!fellDown) { cost += destinationTile->getTUCost(MapData::O_OBJECT, _movementType); } // diagonal walking (uneven directions) costs 50% more tu's if (direction & 1) { cost = (int)((double)cost * 1.5); } } } // for bigger sized units, check the path between part 1,1 and part 0,0 at end position if (size) { Tile *startTile = _save->getTile(*endPosition + Position(1,1,0)); Tile *destinationTile = _save->getTile(*endPosition); int tmpDirection = 7; if (isBlocked(startTile, destinationTile, tmpDirection)) return 255; } return cost; }
int main() { int scale = 3; int counter = 0; int counter2 = 0; int currentDirection = 0; int ballIndex = 0; int score = 0; int outOfBoxCounter = 0; const int maxBallCount = 245; bool wait = true; int positionGhost = 280; bool pinkOutBox = false; Clock boxClock; Clock introClock; Clock afraidClock; enum Status { Stopped, Paused, Playing }; sf::RenderWindow window(sf::VideoMode(224 * scale, 288 *scale), "Pacman"); window.setFramerateLimit(30); //*************************************************** sf::Texture whiteGhost; if (!whiteGhost.loadFromFile("Images/whiteGhost.png")) { cout << "Error\n"; } //pinky: std::vector<Ghost>::iterator ghostIter; std::vector<Ghost> ghostArray; Ghost pink; sf::IntRect rectPinkSprite(0, 0, 24, 24); sf::Texture pinkText; if (!pinkText.loadFromFile("Images/redGhost.png")) { std::cout << "Error\n"; } pink.sprite.setTexture(pinkText); pink.sprite2.setTexture(whiteGhost); pink.sprite.setTextureRect(rectPinkSprite); pink.sprite2.setTextureRect(rectPinkSprite); pink.setPosition(positionGhost, 410); ghostArray.push_back(pink); Ghost inky; sf::IntRect rectInkySprite(0, 0, 24, 24); sf::Texture inkyText; inky.setPosition(positionGhost + 30, 410); if (!inkyText.loadFromFile("Images/blueGhost2.png")) { std::cout << "Error\n"; } inky.sprite.setTexture(inkyText); inky.sprite2.setTexture(whiteGhost); inky.sprite2.setTextureRect(rectInkySprite); inky.sprite.setTextureRect(rectInkySprite); ghostArray.push_back(inky); Ghost blinky; sf::IntRect rectBlinkySprite(0, 0, 24, 24); sf::Texture blinkyText; blinky.setPosition(positionGhost + 60, 410); if (!blinkyText.loadFromFile("Images/pinkGhost.png")) { std::cout << "Error\n"; } blinky.sprite.setTexture(blinkyText); blinky.sprite2.setTexture(whiteGhost); blinky.sprite2.setTextureRect(rectBlinkySprite); blinky.sprite.setTextureRect(rectBlinkySprite); ghostArray.push_back(blinky); Ghost clyde; sf::IntRect rectClydeSprite(0, 0, 24, 24); sf::Texture clydeText; clyde.setPosition(positionGhost + 90, 410); if (!clydeText.loadFromFile("Images/orangeGhost.png")) { std::cout << "Error\n"; } clyde.sprite.setTexture(clydeText); clyde.sprite2.setTexture(whiteGhost); clyde.sprite2.setTextureRect(rectClydeSprite); clyde.sprite.setTextureRect(rectClydeSprite); ghostArray.push_back(clyde); //**************************************************** //*************************************************** //Loading in Map to position the walls std::ifstream fin; fin.open("level.txt"); int val; if (fin.fail()) { cout << "Error couldn't load file" << endl; } //*************************************************** //balls: Ball ball; std::vector<Ball>::iterator ballIter; std::vector<Ball> ballArray; sf::IntRect rectBallSprite(0, 0, 24, 24); sf::Texture ballText; sf::Texture largePalletText; if (!ballText.loadFromFile("Images/pellets.png")) { std::cout << "Error\n"; } if (!largePalletText.loadFromFile("Images/largePellet.png")) { std::cout << "Error\n"; } //*************************************************** // Setting up the tile that represent the walls //Positioning the walls in the map std::vector<Tile>::const_iterator tileIter; std::vector<Tile> tileArray; Tile tile; sf::Vector2i Grid(28 * scale, 36 * scale); for (int y = 0; y < 36; y++) { for (int x = 0; x < 28; x++) { fin >> val; cout << val; if (val == 1) { tile.update(x, y); tileArray.push_back(tile); } //setting coordinates for 250 ball objects in array if (((y >= 4 && y < 12) || (y >= 12 && (x == 6 || x == 21)) || (y >= 23 && y < 34)) && (val == 0) && (ballIndex < maxBallCount)) { ball.setXYPosition(x * 24 + 3, y * 24 + 3); ball.sprite.setTexture(ballText); ball.sprite.setTextureRect(rectBallSprite); ball.setLargePellet(false); ballArray.push_back(ball); ballIndex++; } else if (val == 3) { ball.setXYPosition(x * 24 + 3, y * 24 + 3); ball.sprite.setTexture(largePalletText); ball.sprite.setTextureRect(rectBallSprite); ball.setLargePellet(true); ballArray.push_back(ball); ballIndex++; } } } //Setting up the walls for when pacman goes through the tunnel tile.update(-1, 16); tileArray.push_back(tile); tile.update(28, 16); tileArray.push_back(tile); tile.update(-1, 18); tileArray.push_back(tile); tile.update(28, 18); tileArray.push_back(tile); fin.close(); //**************************************************** //Background Setup: sf::Texture background; if (!background.loadFromFile("Images/pacmanMap.png")) { std::cout << "Error\n"; } sf::Sprite map(background); map.scale(scale, scale); //****************************************************** //Loading up the waka waka sound sf::SoundBuffer playsiren; if (!playsiren.loadFromFile("Sound/Pacman_Siren.wav")) { std::cout << "Couldn't load sound file.\n"; } Sound siren; siren.setBuffer(playsiren); //****************************************************** //Loading up the starting music sf::SoundBuffer buffer; if (!buffer.loadFromFile("Sound/PacmanIntro.wav")) { std::cout << "Couldn't load sound file.\n"; } Sound introMusic; introMusic.setBuffer(buffer); //******************************************************* //Loading up the waka waka sound sf::SoundBuffer wakaWaka; if (!wakaWaka.loadFromFile("Sound/Pacman_Waka_WakaV2.wav")) { std::cout << "Couldn't load sound file.\n"; } Sound waka; waka.setBuffer(wakaWaka); //******************************************************** //Player setup and Loading up the pacman image //Setting up the demensions of the sprite sf::IntRect rectSourceSprite(0, 0, 24, 24); Player player; sf::Texture pacText; if ( !pacText.loadFromFile( "Images/pacmanDirections.png" ) ) { std::cout << "Error\n"; } player.sprite.setTexture(pacText); player.sprite.setTextureRect(rectSourceSprite); //******************************************************** //Lives sf::IntRect rectLiveSprite(24, 0, 24, 24); sf::Sprite live1; live1.setTexture(pacText); live1.setTextureRect(rectLiveSprite); live1.setOrigin(-600, -45); sf::Sprite live2; live2.setTexture(pacText); live2.setTextureRect(rectLiveSprite); live2.setOrigin(-624, -45); //******************************************************** sf::IntRect recCherrieSprite(0, 0, 24, 24); sf::Texture cherrieText; if (!cherrieText.loadFromFile("Images/Cherrie2.png")) { std::cout << "Error\n"; } Character cherrie; cherrie.sprite.setTexture(cherrieText); cherrie.sprite.setTextureRect(recCherrieSprite); cherrie.sprite.setOrigin(-100, -90); //******************************************************** //Set Tiles to Grid sf::Texture setGridTexture; sf::Sprite setGridSprite; setGridSprite.setTexture(setGridTexture); setGridSprite.setColor(sf::Color::Black); //******************************************************* //Creating a Grid //Creating a Texture and a sprite sf::RectangleShape tempGridSpriteOutline; tempGridSpriteOutline.setOutlineColor(sf::Color::White); tempGridSpriteOutline.setOutlineThickness(0.5); tempGridSpriteOutline.setFillColor(sf::Color::Transparent); tempGridSpriteOutline.setSize(sf::Vector2f(8 * scale, 8 * scale)); sf::Font font; if (!font.loadFromFile("pacfont.ttf")) { cout << "fail" << endl; } sf::Font font2; if (!font2.loadFromFile("consola.ttf")) { cout << "fail" << endl; } sf::Text text; text.setFont(font); text.setString("score"); text.setCharacterSize(43); text.setColor(sf::Color::White); text.setOrigin(-40, 0); Menu menu(window.getSize().x, window.getSize().y); Gameover gameover(window.getSize().x, window.getSize().y); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event) || menu.getIsMenuOn()) { if (event.type == sf::Event::Closed) window.close(); //******************************************************************** //Creating the menu if (menu.getIsMenuOn()) { window.clear(); menu.draw(window); window.display(); switch (event.type) { case sf::Event::KeyReleased: switch (event.key.code) { case sf::Keyboard::Up: menu.moveUp(); break; case sf::Keyboard::Down: menu.moveDown(); break; case sf::Keyboard::Return: switch (menu.getPressedItem()) { case 0: wait = true; introMusic.play(); introClock.restart(); menu.setIsMenuOn(false); break; case 1: window.close(); break; } } } }// end of menu if statement } // of event for loop //*********************************************************************** //Display the gameover screen once the player runs out of lives if (player.getLives() <= 1) { sf::RenderWindow window2(sf::VideoMode(224 * scale, 288 * scale), "Game Over"); while (window2.isOpen()) { window.close(); while (window2.pollEvent(event)) { if (event.type == sf::Event::Closed) window2.close(); //******************************************************************** //Creating the menu //window2.clear(); gameover.draw(window2); window2.display(); } } } window.clear(); //drawing background window.draw(map); // this font is for the number, since the other font i downloaded didnt have numbers in it sf::Text mytext; mytext.setFont(font2);//set the object to the new text std::stringstream ss;//converts a interger into a string ss << score; mytext.setString(ss.str().c_str()); mytext.setColor(sf::Color::White); mytext.setCharacterSize(55); mytext.setOrigin(-80, 0); window.draw(mytext); //window.draw(cherrie.sprite); //Draw Grid for (int i = 0; i < Grid.x; i++) { for (int j = 0; j < Grid.y; j++) { tempGridSpriteOutline.setPosition(i * 8 * scale, j * 8 * scale); //window.draw(tempGridSpriteOutline); } } counter = 0; //****************************************************** //Draws tiles throughout the map for (tileIter = tileArray.begin(); tileIter != tileArray.end(); tileIter++) { //window.draw(tileArray[counter].rect); counter++; } //*************************************************** //Allows the player to move player.updateMovement(); player.update(); //***************************************************** //This gets the ghost out of the box at the start of the game. for (ghostIter = ghostArray.begin(); ghostIter < ghostArray.end(); ghostIter++) { if (outOfBoxCounter < 4) { switch (outOfBoxCounter) { case (0) : if (boxClock.getElapsedTime().asSeconds() > 4 && boxClock.getElapsedTime().asSeconds() < 4.6 && !ghostArray[outOfBoxCounter].getOutOfBox()) { ghostArray[outOfBoxCounter].setDirec(2); } else if (boxClock.getElapsedTime().asSeconds() > 4.6 && boxClock.getElapsedTime().asSeconds() < 4.7 && !pinkOutBox) { ghostArray[outOfBoxCounter].setDirec(4); //ghostArray[outOfBoxCounter].setOutOfBox(true); boxClock.restart(); outOfBoxCounter++; } break; case(1) : if (boxClock.getElapsedTime().asSeconds() > 4 && boxClock.getElapsedTime().asSeconds() < 4.2 && !ghostArray[outOfBoxCounter].getOutOfBox()) { ghostArray[outOfBoxCounter].setDirec(2); } else if (boxClock.getElapsedTime().asSeconds() > 4.2 && boxClock.getElapsedTime().asSeconds() < 4.4 && !pinkOutBox) { ghostArray[outOfBoxCounter].setDirec(4); //ghostArray[outOfBoxCounter].setOutOfBox(true); boxClock.restart(); outOfBoxCounter++; } break; case(2) : if (boxClock.getElapsedTime().asSeconds() > 4 && boxClock.getElapsedTime().asSeconds() < 4.2 && !ghostArray[outOfBoxCounter].getOutOfBox()) { ghostArray[outOfBoxCounter].setDirec(3); } else if (boxClock.getElapsedTime().asSeconds() > 4.2 && boxClock.getElapsedTime().asSeconds() < 4.4 && !pinkOutBox) { ghostArray[outOfBoxCounter].setDirec(4); //ghostArray[outOfBoxCounter].setOutOfBox(true); boxClock.restart(); outOfBoxCounter++; } break; case(3) : if (boxClock.getElapsedTime().asSeconds() > 4 && boxClock.getElapsedTime().asSeconds() < 4.5 && !ghostArray[outOfBoxCounter].getOutOfBox()) { ghostArray[outOfBoxCounter].setDirec(3); } else if (boxClock.getElapsedTime().asSeconds() > 4.5 && boxClock.getElapsedTime().asSeconds() < 4.7 && !pinkOutBox) { ghostArray[outOfBoxCounter].setDirec(4); //ghostArray[outOfBoxCounter].setOutOfBox(true); boxClock.restart(); outOfBoxCounter++; } break; } } } //************************************************* //Tunnel mirror if (player.rect.getPosition().x <= -14) { //cout << "Out of the box" << endl; player.rect.setPosition(682, player.rect.getPosition().y); } else if (player.rect.getPosition().x >= 680) { player.rect.setPosition(-15, player.rect.getPosition().y); } //*************************************************** // Wall detection when player collides with a wall counter = 0; for (tileIter = tileArray.begin(); tileIter != tileArray.end(); tileIter++) { if ((player.sprite.getPosition().x >= 300 && player.sprite.getPosition().x <= 360) && (player.sprite.getPosition().y <= 370 && player.sprite.getPosition().y >= 351) && player.getDirection() == 2) { if (player.getDirection() == 2) { player.rect.move(0, -7); break; } } if (player.rect.getGlobalBounds().intersects(tileArray[counter].rect.getGlobalBounds())) { //cout << "Wall HIT AT: "<< tileArray[counter].rect.getPosition().x << "," << tileArray[counter].rect.getPosition().y << endl; currentDirection = player.getDirection(); switch (currentDirection) { case 1: player.rect.move(0, 3); break; case 2: player.rect.move(0, -3); break; case 3: player.rect.move(3, 0); break; case 4: player.rect.move(-3, 0); break; default: break; } } counter++; }//end for loop //******************************************************************** //Changes the direction of the ghost once it hits a wall. counter = 0; counter2 = 0; bool hit = false; for (ghostIter = ghostArray.begin(); ghostIter != ghostArray.end(); ghostIter++) { ghostArray[counter].setHitWall(false); ghostArray[counter].isDownDirectBlock = false; ghostArray[counter].isUpDirectBlock = false; ghostArray[counter].isLeftDirectBlock = false; ghostArray[counter].isRightDirectBlock = false; for (tileIter = tileArray.begin(); tileIter != tileArray.end(); tileIter++) { if(ghostArray[counter].dirRect.getGlobalBounds().intersects(tileArray[counter2].rect.getGlobalBounds())) { ghostArray[counter].setHitWall(true); if (ghostArray[counter].rect.getGlobalBounds().intersects(tileArray[counter2].rect.getGlobalBounds()) && ghostArray[counter].getOutOfBox()) { //cout << "Wall hit" << counter << endl; //currentDirection = player.getDirection(); switch (ghostArray[counter].getDirection2()) { case 1: ghostArray[counter].rect.move(0, -3); //ghostArray[counter].setDirec(4); break; case 2: ghostArray[counter].rect.move(-3, 0); //ghostArray[counter].setDirec(3); break; case 3: ghostArray[counter].rect.move(3, 0); //ghostArray[counter].setDirec(2); break; case 4: ghostArray[counter].rect.move(0, 3); //ghostArray[counter].setDirec(1); break; default: break; } } } if (ghostArray[counter].upRect.getGlobalBounds().intersects(tileArray[counter2].rect.getGlobalBounds()) && (ghostArray[counter].dirRect.getGlobalBounds().intersects(tileArray[counter2].rect.getGlobalBounds()))) { ghostArray[counter].isUpDirectBlock = true; ghostArray[counter].setOutOfBox(true); hit = true; //ghostArray[counter].rect.move(0, 3); } if (ghostArray[counter].downRect.getGlobalBounds().intersects(tileArray[counter2].rect.getGlobalBounds()) && (/*ghostArray[counter].rect.getGlobalBounds().intersects(tileArray[counter2].rect.getGlobalBounds())) &&*/ ghostArray[counter].getOutOfBox())) { ghostArray[counter].isDownDirectBlock = true; //ghostArray[counter].rect.move(0, -3); } if (ghostArray[counter].rightRect.getGlobalBounds().intersects(tileArray[counter2].rect.getGlobalBounds()) && (/*ghostArray[counter].rect.getGlobalBounds().intersects(tileArray[counter2].rect.getGlobalBounds())) &&*/ ghostArray[counter].getOutOfBox())) { ghostArray[counter].isRightDirectBlock = true; //ghostArray[counter].rect.move(-3, 0); } if (ghostArray[counter].leftRect.getGlobalBounds().intersects(tileArray[counter2].rect.getGlobalBounds()) && (/*ghostArray[counter].rect.getGlobalBounds().intersects(tileArray[counter2].rect.getGlobalBounds())) &&*/ ghostArray[counter].getOutOfBox())) { ghostArray[counter].isLeftDirectBlock = true; //ghostArray[counter].rect.move(3, 0); } ghostArray[counter].update(); if (ghostArray[counter].getOutOfBox() && ghostArray[counter].getHitWall()) { //cout << "Wall hit" << endl; ghostArray[counter].randomMovement(); } counter2++; }//end inside for loop /* window.draw(ghostArray[counter].rect); window.draw(ghostArray[counter].upRect); window.draw(ghostArray[counter].downRect); window.draw(ghostArray[counter].leftRect); window.draw(ghostArray[counter].rightRect); window.draw(ghostArray[counter].dirRect); */ counter2 = 0; counter++; }// end for loop //*************************************************** //This where the ghost are allowed to move. counter = 0; for (ghostIter = ghostArray.begin(); ghostIter != ghostArray.end(); ghostIter++) { ghostArray[counter].moving1(); counter++; } //*************************************************** // If the ghost are blue and eaten by pacman, then the ghost are placed back inside the box counter = 0; if (ghostArray[0].getIsAfraid()) { for (ghostIter = ghostArray.begin(); ghostIter != ghostArray.end(); ghostIter++) { //send the ghost back inside the box if (player.sprite.getGlobalBounds().intersects(ghostArray[counter].sprite.getGlobalBounds())) { ghostArray[counter].setOutOfBox(false); ghostArray[counter].setPosition(positionGhost + 60, 410); score = score + 100; break; } counter++; } } //*************************************************** //player touches ghost decrease the lifes by one int counter = 0; for (ghostIter = ghostArray.begin(); ghostIter != ghostArray.end(); ghostIter++) { //decrements lives if pacman hits ghost if (player.sprite.getGlobalBounds().intersects(ghostArray[counter].sprite.getGlobalBounds()) && !ghostArray[counter].getIsAfraid()) { player.sprite.setPosition(sf::Vector2f(14 * 24, 20 * 24 + 4)); player.rect.setPosition(sf::Vector2f(14 * 24, 20 * 24 + 4)); if (player.getLives() == 2) { live1.setOrigin(30, 0); player.setLives(player.getLives() - 1); } //player.sprite.setOrigin(14 * 24, 20 * 24 + 4); else if (player.getLives()> 1) { live2.setOrigin(30, 0); //player.sprite.setOrigin(14 * 24, 20 * 24 + 4); player.setLives(player.getLives() - 1); } } counter++; } //GameOver Display if (player.getLives() <= 0) { window.close(); window.clear(); gameover.draw(window); window.display(); }// end of menu if statement //*************************************************** // If player intersects with ball: counter = 0; counter2 = 0; for (ballIter = ballArray.begin(); ballIter != ballArray.end(); ballIter++) { if (player.rect.getGlobalBounds().intersects(ballArray[counter].rect.getGlobalBounds())) { ballArray[counter].setIsShowing(false); //Turn the ghost blue if the pacman eats a large pallet if (ballArray[counter].getIsLargePellet()) { afraidClock.restart(); for (ghostIter = ghostArray.begin(); ghostIter != ghostArray.end(); ghostIter++) { ghostArray[counter2].setIsAfraid(true); counter2++; } counter2 = 0; } if (introClock.getElapsedTime().asSeconds() >= 0.41)//introClock restarts { waka.play(); //siren.stop(); introClock.restart(); } score++; } counter++; }// end for loop //This deletes the ball from the map counter = 0; for (ballIter = ballArray.begin(); ballIter != ballArray.end(); ballIter++) { if (!ballArray[counter].getIsShowing()) { ballArray.erase(ballIter); break; } counter++; }// end for loop //************************************************** //************************************************** //reset ghost to their original sprite once time runs out counter = 0; if (afraidClock.getElapsedTime().asSeconds() > 8.0) { for (ghostIter = ghostArray.begin(); ghostIter != ghostArray.end(); ghostIter++) { ghostArray[counter].setIsAfraid(false); counter++; } } //************************************************** // If the siren is paused, unpause it if (siren.getStatus() == 0 && introClock.getElapsedTime().asSeconds() > 0.47) { siren.play(); } //*************************************************** //cherrie if (player.rect.getGlobalBounds().intersects(cherrie.sprite.getGlobalBounds())) { score += 100; cherrie.sprite.setPosition(-100, -50); } //ball drawn to screen: counter = 0; for (ballIter = ballArray.begin(); ballIter != ballArray.end(); ballIter++) { if (ballArray[counter].getIsShowing() == true) { window.draw(ballArray[counter].sprite); ballArray[counter].update(); //window.draw(ballArray[ix].rect); } counter ++; } //************************************************************** //window.draw(player.rect2); //drawing the player sprite window.draw(player.sprite); //drawint the lives window.draw(live1); window.draw(live2); window.draw(cherrie.sprite); //window.draw(player.rect); //cout << "Player position: " << player.rect.getPosition().x << ", " << player.rect.getPosition().y << endl; //**************************************************************** //Draws ghost to the screen. If they are afraid then the blue sprite shows up instead counter = 0; for (ghostIter = ghostArray.begin(); ghostIter != ghostArray.end(); ghostIter++) { if (!ghostArray[counter].getIsAfraid()) { window.draw(ghostArray[counter].sprite); } else { window.draw(ghostArray[counter].sprite2); } //window.draw(ghostArray[counter].rect); counter++; } //********************************************************* //********************************************************* window.display(); while (introClock.getElapsedTime().asSeconds() <= 4.0 && wait) { boxClock.restart(); } if (introClock.getElapsedTime().asSeconds() >= 4.1 && wait) { siren.setLoop(true); siren.play(); } wait = false; if (player.getLives() < 1) { introClock.restart(); while (introClock.getElapsedTime().asSeconds() < 6.0) { gameover.draw(window); window.display(); } wait = true; } //cout << ballArray.size() << endl; } return 0; }
/** * Draws the minimap. */ void MiniMapView::draw() { int _startX = _camera->getCenterPosition().x - ((getWidth() / CELL_WIDTH) / 2); int _startY = _camera->getCenterPosition().y - ((getHeight() / CELL_HEIGHT) / 2); InteractiveSurface::draw(); if (!_set) { return; } drawRect(0, 0, getWidth(), getHeight(), 0); this->lock(); for (int lvl = 0; lvl <= _camera->getCenterPosition().z; lvl++) { int py = _startY; for (int y = Surface::getY(); y < getHeight() + Surface::getY(); y += CELL_HEIGHT) { int px = _startX; for (int x = Surface::getX(); x < getWidth() + Surface::getX(); x += CELL_WIDTH) { MapData * data = 0; Tile * t = 0; Position p (px, py, lvl); t = _battleGame->getTile(p); if (!t) { px++; continue; } if (t->isDiscovered(2)) { for (int i = 0; i < 4; i++) { data = t->getMapData(i); Surface * s = 0; if (data && data->getMiniMapIndex()) { s = _set->getFrame (data->getMiniMapIndex()+35); } if (s) { s->blitNShade(this, x, y, t->getShade()); } } } // alive units if (t->getUnit() && t->getUnit()->getVisible()) { int frame = t->getUnit()->getMiniMapSpriteIndex(); int size = t->getUnit()->getArmor()->getSize(); frame += (t->getPosition().y - t->getUnit()->getPosition().y) * size; frame += t->getPosition().x - t->getUnit()->getPosition().x; frame += _frame * size * size; Surface * s = _set->getFrame(frame); s->blitNShade(this, x, y, 0); } // perhaps (at least one) item on this tile? if (t->isDiscovered(2) && !t->getInventory()->empty()) { int frame = 9 + _frame; Surface * s = _set->getFrame(frame); s->blitNShade(this, x, y, 0); } px++; } py++; } } this->unlock(); int centerX = getWidth() / 2 - 1; int centerY = getHeight() / 2 - 1; Uint8 color = 1 + _frame * 3; int xOffset = CELL_WIDTH / 2; int yOffset = CELL_HEIGHT / 2; drawLine(centerX - CELL_WIDTH, centerY - CELL_HEIGHT, centerX - xOffset, centerY - yOffset, color); // top left drawLine(centerX + xOffset, centerY - yOffset, centerX + CELL_WIDTH, centerY - CELL_HEIGHT, color); // top right drawLine(centerX - CELL_WIDTH, centerY + CELL_HEIGHT, centerX - xOffset, centerY + yOffset, color); // bottom left drawLine(centerX + CELL_WIDTH, centerY + CELL_HEIGHT, centerX + xOffset, centerY + yOffset, color); //bottom right }
void Tileset::Parse(const tinyxml2::XMLNode *tilesetNode, const std::string& file_path) { const tinyxml2::XMLElement *tilesetElem = tilesetNode->ToElement(); // Read all the attributes into local variables. // The firstgid and source attribute are kept in the TMX map, // since they are map specific. first_gid = tilesetElem->IntAttribute("firstgid"); // If the <tileset> node contains a 'source' tag, // the tileset config should be loaded from an external // TSX (Tile Set XML) file. That file has the same structure // as the <tileset> element in the TMX map. const char* source_name = tilesetElem->Attribute("source"); tinyxml2::XMLDocument tileset_doc; if ( source_name ) { std::string fileName = file_path + source_name; tileset_doc.LoadFile( fileName.c_str() ); if ( tileset_doc.ErrorID() != 0) { fprintf(stderr, "failed to load tileset file '%s'\n", fileName.c_str()); return; } // Update node and element references to the new node tilesetNode = tileset_doc.FirstChildElement("tileset"); tilesetElem = tilesetNode->ToElement(); } tile_width = tilesetElem->IntAttribute("tilewidth"); tile_height = tilesetElem->IntAttribute("tileheight"); margin = tilesetElem->IntAttribute("margin"); spacing = tilesetElem->IntAttribute("spacing"); name = tilesetElem->Attribute("name"); // Parse the tile offset, if it exists. const tinyxml2::XMLNode *tileOffsetNode = tilesetNode->FirstChildElement("tileoffset"); if (tileOffsetNode) { tileOffset = new TileOffset(); tileOffset->Parse(tileOffsetNode); } // Parse the terrain types if any. const tinyxml2::XMLNode *terrainTypesNode = tilesetNode->FirstChildElement("terraintypes"); if (terrainTypesNode) { TerrainArray terrainArray; terrainArray.Parse(&terrainTypes, terrainTypesNode); } // Parse the image. const tinyxml2::XMLNode *imageNode = tilesetNode->FirstChildElement("image"); if (imageNode) { image = new Image(); image->Parse(imageNode); } // Iterate through all of the tile elements and parse each. const tinyxml2::XMLNode *tileNode = tilesetNode->FirstChildElement("tile"); for (int tId = 0; tileNode; ++tId) { Tile* tile = new Tile(tId); tile->Parse(tileNode); tiles.push_back(tile); tileNode = tileNode->NextSiblingElement("tile"); } // Parse the properties if any. const tinyxml2::XMLNode *propertiesNode = tilesetNode->FirstChildElement("properties"); if (propertiesNode) { properties.Parse(propertiesNode); } }
void IOMapBin::loadOTM(Map* map) { int op; bool end = false; while(!feof(fh) || !end) { op = fgetc(fh); switch(op) { case 0x10: // Information of the map { char name[100], author[100]; int pos; int len; // Map Name len = fgetc(fh); for (pos = 0; pos < len; pos++) name[pos] = fgetc(fh); name[pos] = '\0'; std::cout << ":: Map Name: " << name << std::endl; // Map Author len = fgetc(fh); for (pos = 0; pos < len; pos++) author[pos] = fgetc(fh); author[pos] = '\0'; std::cout << ":: Map Author: " << author << std::endl; } break; case 0x20: // Map dimensions { int width, height; width = fgetc(fh); width += fgetc(fh)<<8; height = fgetc(fh); height += fgetc(fh)<<8; map->mapwidth = width; map->mapheight = height; std::cout << ":: Map dimensions: " << width << "x" << height << std::endl; } break; case 0x30: // Global Temple Position { PositionEx templePos; templePos.x = fgetc(fh); templePos.x += fgetc(fh); // X templePos.y = fgetc(fh); templePos.y += fgetc(fh); // Y templePos.z = fgetc(fh); // Z int radius = fgetc(fh); // Radius // TODO: use the temple point and radius std::cout << ":: Global Temple Position: " << templePos.x << " " << templePos.y << " " << templePos.z << " Radius: " << radius << std::endl; } break; case 0x40: // Tiles and items { Tile *t; int x, y, z, id, total = 0; while(true) { // tile pos x = fgetc(fh); x += fgetc(fh) << 8; y = fgetc(fh); y += fgetc(fh) << 8; z = fgetc(fh); // end the loop if (x == 0xFFFF && y == 0xFFFF && z == 0xFF) break; id = fgetc(fh) + 100; id += fgetc(fh) << 8; total += 1; map->setTile(x, y, z, id); t = map->getTile(x, y, z); // check if the tile is pz if (fgetc(fh) == 1) t->setPz(); int op2; int tmpid; do { op2 = fgetc(fh); switch (op2) { case 0x10: // Action Id fgetc(fh); // len tmpid = fgetc(fh); tmpid += fgetc(fh) << 8; // t->ground->setActionId(tmpid); break; case 0x20: // Unique Id fgetc(fh); // len tmpid = fgetc(fh); tmpid += fgetc(fh) << 8; //t ->ground->setUniqueId(tmpid); break; case 0x30: // Target Id fgetc(fh); // len tmpid = fgetc(fh); tmpid += fgetc(fh) << 8; // TODO: implement target ids break; case 0xA0: // Item { int itemcount = fgetc(fh); for (int count = 0; count < itemcount; count++) { int itemid = fgetc(fh) + 100; itemid += fgetc(fh) << 8; Item *item = Item::CreateItem(itemid); int op3; do { op3 = fgetc(fh); switch (op3) { case 0x10: // Count fgetc(fh); //len item->setItemCountOrSubtype((unsigned char)fgetc(fh)); break; case 0x20: // Action Id fgetc(fh); //len tmpid = fgetc(fh); tmpid += fgetc(fh) << 8; // item->setActionId(tmpid); break; case 0x30: // Unique Id fgetc(fh); //len tmpid = fgetc(fh); tmpid += fgetc(fh) << 8; // item->setUniqueId(tmpid); break; case 0x40: // Target Id fgetc(fh); //len tmpid = fgetc(fh); tmpid += fgetc(fh) << 8; // item->setTargetId(tmpid); break; case 0x70: //Teleport { Teleport *tele = dynamic_cast<Teleport*>(item); Position toPos; fgetc(fh); //len toPos.x = fgetc(fh); toPos.x += fgetc(fh)<<8; toPos.y = fgetc(fh); toPos.y += fgetc(fh)<<8; toPos.z = fgetc(fh); if (tele) tele->setDestPos(toPos); } break; case 0x80: // Fluids fgetc(fh); if (item->isFluidContainer()) item->setItemCountOrSubtype((unsigned char)fgetc(fh)); else fgetc(fh); break; case 0xFF: // End break; default: // Unknow/New operators { printf("WARNING: Unknown operator loading items: 0x%X!\n",op3); int len = fgetc(fh); for (int i = 0; i < len; i++) fgetc(fh); } break; } } while (op3 < 0xFF); //item->pos.x = x; //item->pos.y = y; //item->pos.z = z; if (item->isAlwaysOnTop()) t->topItems.push_back(item); else t->downItems.push_back(item); } } break; case 0xFF: // End break; default: // Unknow/New operators { printf("WARNING: Unknown operator loading tiles: 0x%X!\n",op2); int len = fgetc(fh); for (int i = 0;i < len; i++) fgetc(fh); } break; } } while (op2 < 0xFF); } std::cout << ":: Total of tiles loaded is " << total << std::endl; } break; case 0x50: // Spawns { SpawnManager::initialize(&g_game); Position pos; int cx, cy, radius, total=0; long int secs; std::string cname; int num = fgetc(fh); num+=fgetc(fh)<<8; for (int i = 0; i < num; i++) { int len = fgetc(fh); int count; cname = ""; for (int j = 0;j < len; j++) cname.push_back(fgetc(fh)); // get the creature name //std::cout << cname.c_str() << std::endl; pos.x = fgetc(fh); pos.x += fgetc(fh) << 8; pos.y = fgetc(fh); pos.y += fgetc(fh) << 8; pos.z = fgetc(fh); radius = fgetc(fh) + 1; count = fgetc(fh); // number of creatures in this respawn total += count; secs = fgetc(fh); secs += fgetc(fh) << 8; Spawn *spawn = new Spawn(&g_game, pos, radius); SpawnManager::instance()->addSpawn(spawn); for (int j = 0; j < count; j++) { cx = (rand() % (radius * 2)) - radius; cy = (rand() % (radius * 2)) - radius; spawn->addMonster(cname, NORTH, cx, cy, secs * 1000); } fgetc(fh); // 1 = check for players near, 0 = dont check } std::cout << ":: Loaded spawns: " << total << std::endl; SpawnManager::instance()->startup(); } break; case 0xF0: end = true; break; } } fclose(fh); return; }
void Build::_updatePreviewTiles( bool force ) { __D_REF(d,Build); Tile* curTile = _camera()->at( _lastCursorPos(), true ); if( !curTile ) return; if( !force && d.lastTilePos == curTile->epos() ) return; if( !d.multiBuilding ) { _setStartCursorPos( _lastCursorPos() ); d.startTilePos = curTile->pos(); } d.lastTilePos = curTile->epos(); _discardPreview(); d.money4Construction = 0; if( d.borderBuilding ) { Tile* startTile = _camera()->at( d.startTilePos ); // tile under the cursor (or NULL) Tile* stopTile = _camera()->at( _lastCursorPos(), true ); TilesArray pathTiles = RoadPropagator::createPath( _city()->tilemap(), startTile->epos(), stopTile->epos(), d.roadAssignment, d.kbShift ); Tilemap& tmap = _city()->tilemap(); TilePos leftUpCorner = pathTiles.leftUpCorner(); TilePos rigthDownCorner = pathTiles.rightDownCorner(); TilePos leftDownCorner( leftUpCorner.i(), rigthDownCorner.j() ); TilesArray ret; int mmapSize = std::max<int>( leftUpCorner.j() - rigthDownCorner.j() + 1, rigthDownCorner.i() - leftUpCorner.i() + 1 ); for( int y=0; y < mmapSize; y++ ) { for( int t=0; t <= y; t++ ) { TilePos tpos = leftDownCorner + TilePos( t, mmapSize - 1 - ( y - t ) ); if( pathTiles.contain( tpos ) ) ret.push_back( &tmap.at( tpos ) ); } } for( int x=1; x < mmapSize; x++ ) { for( int t=0; t < mmapSize-x; t++ ) { TilePos tpos = leftDownCorner + TilePos( x + t, t ); if( pathTiles.contain( tpos ) ) ret.push_back( &tmap.at( tpos ) ); } } pathTiles = ret; for( auto tile : pathTiles ) _checkPreviewBuild( tile->epos() ); } else { TilesArray tiles = _getSelectedArea( d.startTilePos ); for( auto tile : tiles ) _checkPreviewBuild( tile->epos() ); } d.sortBuildTiles(); d.text.image.fill( ColorList::clear, Rect() ); d.text.font.setColor( ColorList::red ); d.text.font.draw( d.text.image, fmt::format( "{} Dn", d.money4Construction ), Point() ); }
bool IOMapSerialize::loadItem(PropStream& propStream, Cylinder* parent) { uint16_t id; if (!propStream.read<uint16_t>(id)) { return false; } Tile* tile = nullptr; if (parent->getParent() == nullptr) { tile = parent->getTile(); } const ItemType& iType = Item::items[id]; if (iType.moveable || !tile) { //create a new item Item* item = Item::CreateItem(id); if (item) { if (item->unserializeAttr(propStream)) { Container* container = item->getContainer(); if (container && !loadContainer(propStream, container)) { delete item; return false; } parent->internalAddThing(item); item->startDecaying(); } else { std::cout << "WARNING: Unserialization error in IOMapSerialize::loadItem()" << id << std::endl; delete item; return false; } } } else { // Stationary items like doors/beds/blackboards/bookcases Item* item = nullptr; if (const TileItemVector* items = tile->getItemList()) { for (Item* findItem : *items) { if (findItem->getID() == id) { item = findItem; break; } else if (iType.isDoor() && findItem->getDoor()) { item = findItem; break; } else if (iType.isBed() && findItem->getBed()) { item = findItem; break; } } } if (item) { if (item->unserializeAttr(propStream)) { Container* container = item->getContainer(); if (container && !loadContainer(propStream, container)) { return false; } g_game.transformItem(item, id); } else { std::cout << "WARNING: Unserialization error in IOMapSerialize::loadItem()" << id << std::endl; } } else { //The map changed since the last save, just read the attributes std::unique_ptr<Item> dummy(Item::CreateItem(id)); if (dummy) { dummy->unserializeAttr(propStream); Container* container = dummy->getContainer(); if (container) { if (!loadContainer(propStream, container)) { return false; } } else if (BedItem* bedItem = dynamic_cast<BedItem*>(dummy.get())) { uint32_t sleeperGUID = bedItem->getSleeper(); if (sleeperGUID != 0) { g_game.removeBedSleeper(sleeperGUID); } } } } } return true; }
Tile* Tile::queryDestination(int32_t&, const Thing&, Item** destItem, uint32_t& flags) { Tile* destTile = nullptr; *destItem = nullptr; if (floorChangeDown()) { uint16_t dx = tilePos.x; uint16_t dy = tilePos.y; uint8_t dz = tilePos.z + 1; Tile* southDownTile = g_game.map.getTile(dx, dy - 1, dz); if (southDownTile && southDownTile->floorChange(DIRECTION_SOUTH_ALT)) { dy -= 2; destTile = g_game.map.getTile(dx, dy, dz); } else { Tile* eastDownTile = g_game.map.getTile(dx - 1, dy, dz); if (eastDownTile && eastDownTile->floorChange(DIRECTION_EAST_ALT)) { dx -= 2; destTile = g_game.map.getTile(dx, dy, dz); } else { Tile* downTile = g_game.map.getTile(dx, dy, dz); if (downTile) { if (downTile->floorChange(DIRECTION_NORTH)) { ++dy; } if (downTile->floorChange(DIRECTION_SOUTH)) { --dy; } if (downTile->floorChange(DIRECTION_SOUTH_ALT)) { dy -= 2; } if (downTile->floorChange(DIRECTION_EAST)) { --dx; } if (downTile->floorChange(DIRECTION_EAST_ALT)) { dx -= 2; } if (downTile->floorChange(DIRECTION_WEST)) { ++dx; } destTile = g_game.map.getTile(dx, dy, dz); } } } } else if (floorChange()) { uint16_t dx = tilePos.x; uint16_t dy = tilePos.y; uint8_t dz = tilePos.z - 1; if (floorChange(DIRECTION_NORTH)) { --dy; } if (floorChange(DIRECTION_SOUTH)) { ++dy; } if (floorChange(DIRECTION_EAST)) { ++dx; } if (floorChange(DIRECTION_WEST)) { --dx; } if (floorChange(DIRECTION_SOUTH_ALT)) { dy += 2; } if (floorChange(DIRECTION_EAST_ALT)) { dx += 2; } destTile = g_game.map.getTile(dx, dy, dz); } if (destTile == nullptr) { destTile = this; } else { flags |= FLAG_NOLIMIT; //Will ignore that there is blocking items/creatures } if (destTile) { Thing* destThing = destTile->getTopDownItem(); if (destThing) { *destItem = destThing->getItem(); } } return destTile; }
void CivilianBAIState::setupEscape() { int unitsSpottingMe = getSpottingUnits(_unit->getPosition()); int currentTilePreference = 15; int tries = 0; bool coverFound = false; selectNearestTarget(); int dist = _aggroTarget ? _save->getTileEngine()->distance(_unit->getPosition(), _aggroTarget->getPosition()) : 0; int bestTileScore = -100000; int score = -100000; Position bestTile(0, 0, 0); Tile *tile = 0; // weights of various factors in choosing a tile to which to withdraw const int EXPOSURE_PENALTY = 10; const int FIRE_PENALTY = 40; const int BASE_SYSTEMATIC_SUCCESS = 100; const int BASE_DESPERATE_SUCCESS = 110; const int FAST_PASS_THRESHOLD = 100; // a score that's good engouh to quit the while loop early; it's subjective, hand-tuned and may need tweaking int tu = _unit->getTimeUnits() / 2; std::vector<int> reachable = _save->getPathfinding()->findReachable(_unit, tu); std::vector<Position> randomTileSearch = _save->getTileSearch(); RNG::shuffle(randomTileSearch); while (tries < 150 && !coverFound) { _escapeAction->target = _unit->getPosition(); // start looking in a direction away from the enemy if (!_save->getTile(_escapeAction->target)) { _escapeAction->target = _unit->getPosition(); // cornered at the edge of the map perhaps? } score = 0; if (tries < 121) { // looking for cover _escapeAction->target.x += randomTileSearch[tries].x; _escapeAction->target.y += randomTileSearch[tries].y; score = BASE_SYSTEMATIC_SUCCESS; if (_escapeAction->target == _unit->getPosition()) { if (unitsSpottingMe > 0) { // maybe don't stay in the same spot? move or something if there's any point to it? _escapeAction->target.x += RNG::generate(-20,20); _escapeAction->target.y += RNG::generate(-20,20); } else { score += currentTilePreference; } } } else { if (tries == 121) { if (_traceAI) { Log(LOG_INFO) << "best score after systematic search was: " << bestTileScore; } } score = BASE_DESPERATE_SUCCESS; // ruuuuuuun _escapeAction->target = _unit->getPosition(); _escapeAction->target.x += RNG::generate(-10,10); _escapeAction->target.y += RNG::generate(-10,10); _escapeAction->target.z = _unit->getPosition().z + RNG::generate(-1,1); if (_escapeAction->target.z < 0) { _escapeAction->target.z = 0; } else if (_escapeAction->target.z >= _save->getMapSizeZ()) { _escapeAction->target.z = _unit->getPosition().z; } } tries += 10; // civilians shouldn't have any tactical sense anyway so save some CPU cycles here // THINK, DAMN YOU tile = _save->getTile(_escapeAction->target); int distanceFromTarget = _aggroTarget ? _save->getTileEngine()->distance(_aggroTarget->getPosition(), _escapeAction->target) : 0; if (dist >= distanceFromTarget) { score -= (distanceFromTarget - dist) * 10; } else { score += (distanceFromTarget - dist) * 10; } int spotters = 0; if (!tile) { score = -100001; // no you can't quit the battlefield by running off the map. } else { spotters = getSpottingUnits(_escapeAction->target); if (std::find(reachable.begin(), reachable.end(), _save->getTileIndex(tile->getPosition())) == reachable.end()) continue; // just ignore unreachable tiles if (_spottingEnemies || spotters) { if (_spottingEnemies <= spotters) { score -= (1 + spotters - _spottingEnemies) * EXPOSURE_PENALTY; // that's for giving away our position } else { score += (_spottingEnemies - spotters) * EXPOSURE_PENALTY; } } if (tile->getFire()) { score -= FIRE_PENALTY; } if (_traceAI) { tile->setMarkerColor(score < 0 ? 3 : (score < FAST_PASS_THRESHOLD/2 ? 8 : (score < FAST_PASS_THRESHOLD ? 9 : 5))); tile->setPreview(10); tile->setTUMarker(score); } } if (tile && score > bestTileScore) { // calculate TUs to tile; we could be getting this from findReachable() somehow but that would break something for sure... _save->getPathfinding()->calculate(_unit, _escapeAction->target, 0, tu); if (_escapeAction->target == _unit->getPosition() || _save->getPathfinding()->getStartDirection() != -1) { bestTileScore = score; bestTile = _escapeAction->target; _escapeTUs = _save->getPathfinding()->getTotalTUCost(); if (_escapeAction->target == _unit->getPosition()) { _escapeTUs = 1; } if (_traceAI) { tile->setMarkerColor(score < 0 ? 7 : (score < FAST_PASS_THRESHOLD/2 ? 10 : (score < FAST_PASS_THRESHOLD ? 4 : 5))); tile->setPreview(10); tile->setTUMarker(score); } } _save->getPathfinding()->abortPath(); if (bestTileScore > FAST_PASS_THRESHOLD) coverFound = true; // good enough, gogogo } } _escapeAction->target = bestTile; if (_traceAI) { _save->getTile(_escapeAction->target)->setMarkerColor(13); } if (bestTileScore <= -100000) { if (_traceAI) { Log(LOG_INFO) << "Escape estimation failed."; } _escapeAction->type = BA_RETHINK; // do something, just don't look dumbstruck :P return; } else { if (_traceAI) { Log(LOG_INFO) << "Escape estimation completed after " << tries << " tries, " << _save->getTileEngine()->distance(_unit->getPosition(), bestTile) << " squares or so away."; } _escapeAction->type = BA_WALK; } }
int Projectile::calculateTrajectory(double accuracy, Position originVoxel) { Tile *targetTile = _save->getTile(_action.target); BattleUnit *bu = _action.actor; int test = _save->getTileEngine()->calculateLine(originVoxel, _targetVoxel, false, &_trajectory, bu); if (test != V_EMPTY && !_trajectory.empty() && _action.actor->getFaction() == FACTION_PLAYER && _action.autoShotCounter == 1 && ((SDL_GetModState() & KMOD_CTRL) == 0 || !Options::forceFire) && _save->getBattleGame()->getPanicHandled() && _action.type != BA_LAUNCH) { Position hitPos = Position(_trajectory.at(0).x/16, _trajectory.at(0).y/16, _trajectory.at(0).z/24); if (test == V_UNIT && _save->getTile(hitPos) && _save->getTile(hitPos)->getUnit() == 0) //no unit? must be lower { hitPos = Position(hitPos.x, hitPos.y, hitPos.z-1); } if (hitPos != _action.target && _action.result.empty()) { if (test == V_NORTHWALL) { if (hitPos.y - 1 != _action.target.y) { _trajectory.clear(); return V_EMPTY; } } else if (test == V_WESTWALL) { if (hitPos.x - 1 != _action.target.x) { _trajectory.clear(); return V_EMPTY; } } else if (test == V_UNIT) { BattleUnit *hitUnit = _save->getTile(hitPos)->getUnit(); BattleUnit *targetUnit = targetTile->getUnit(); if (hitUnit != targetUnit) { _trajectory.clear(); return V_EMPTY; } } else { _trajectory.clear(); return V_EMPTY; } } } _trajectory.clear(); bool extendLine = true; // even guided missiles drift, but how much is based on // the shooter's faction, rather than accuracy. if (_action.type == BA_LAUNCH) { if (_action.actor->getFaction() == FACTION_PLAYER) { accuracy = 0.60; } else { accuracy = 0.55; } extendLine = _action.waypoints.size() <= 1; } // apply some accuracy modifiers. // This will results in a new target voxel applyAccuracy(originVoxel, &_targetVoxel, accuracy, false, targetTile, extendLine); // finally do a line calculation and store this trajectory. return _save->getTileEngine()->calculateLine(originVoxel, _targetVoxel, true, &_trajectory, bu); }
std::shared_ptr<TileData> ClientGeoJsonSource::parse(const Tile& _tile, std::vector<char>& _rawData) const { if (!m_store) { return nullptr; } auto data = std::make_shared<TileData>(); auto id = _tile.getID(); auto tile = m_store->getTile(id.z, id.x, id.y); // uses a mutex lock internally for thread-safety Layer layer(""); // empty name will skip filtering by 'collection' for (auto& it : tile.features) { Feature feat(m_id); const auto& geom = it.tileGeometry; const auto type = it.type; switch (type) { case geojsonvt::TileFeatureType::Point: { feat.geometryType = GeometryType::points; for (const auto& pt : geom) { const auto& point = pt.get<geojsonvt::TilePoint>(); feat.points.push_back(transformPoint(point)); } break; } case geojsonvt::TileFeatureType::LineString: { feat.geometryType = GeometryType::lines; for (const auto& r : geom) { Line line; for (const auto& pt : r.get<geojsonvt::TileRing>().points) { line.push_back(transformPoint(pt)); } feat.lines.emplace_back(std::move(line)); } break; } case geojsonvt::TileFeatureType::Polygon: { feat.geometryType = GeometryType::polygons; for (const auto& r : geom) { Line line; for (const auto& pt : r.get<geojsonvt::TileRing>().points) { line.push_back(transformPoint(pt)); } // Polygons are in a flat list of rings, with ccw rings indicating // the beginning of a new polygon if (signedArea(line) >= 0 || feat.polygons.empty()) { feat.polygons.emplace_back(); } feat.polygons.back().push_back(std::move(line)); } break; } default: break; } feat.props = *it.tags.map; layer.features.emplace_back(std::move(feat)); } data->layers.emplace_back(std::move(layer)); return data; }
bool WeaponDistance::useWeapon(Player* player, Item* item, Creature* target) const { int32_t damageModifier; const ItemType& it = Item::items[id]; if (it.weaponType == WEAPON_AMMO) { Item* mainWeaponItem = player->getWeapon(true); const Weapon* mainWeapon = g_weapons->getWeapon(mainWeaponItem); if (mainWeapon) { damageModifier = mainWeapon->playerWeaponCheck(player, target, mainWeaponItem->getShootRange()); } else { damageModifier = playerWeaponCheck(player, target, mainWeaponItem->getShootRange()); } } else { damageModifier = playerWeaponCheck(player, target, item->getShootRange()); } if (damageModifier == 0) { return false; } int32_t chance; if (it.hitChance == 0) { //hit chance is based on distance to target and distance skill uint32_t skill = player->getSkillLevel(SKILL_DISTANCE); const Position& playerPos = player->getPosition(); const Position& targetPos = target->getPosition(); uint32_t distance = std::max<uint32_t>(Position::getDistanceX(playerPos, targetPos), Position::getDistanceY(playerPos, targetPos)); uint32_t maxHitChance; if (it.maxHitChance != -1) { maxHitChance = it.maxHitChance; } else if (it.ammoType != AMMO_NONE) { //hit chance on two-handed weapons is limited to 90% maxHitChance = 90; } else { //one-handed is set to 75% maxHitChance = 75; } if (maxHitChance == 75) { //chance for one-handed weapons switch (distance) { case 1: case 5: chance = std::min<uint32_t>(skill, 74) + 1; break; case 2: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 28) * 2.40f) + 8; break; case 3: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 45) * 1.55f) + 6; break; case 4: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 58) * 1.25f) + 3; break; case 6: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 90) * 0.80f) + 3; break; case 7: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 104) * 0.70f) + 2; break; default: chance = it.hitChance; break; } } else if (maxHitChance == 90) { //formula for two-handed weapons switch (distance) { case 1: case 5: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 74) * 1.20f) + 1; break; case 2: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 28) * 3.20f); break; case 3: chance = std::min<uint32_t>(skill, 45) * 2; break; case 4: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 58) * 1.55f); break; case 6: case 7: chance = std::min<uint32_t>(skill, 90); break; default: chance = it.hitChance; break; } } else if (maxHitChance == 100) { switch (distance) { case 1: case 5: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 73) * 1.35f) + 1; break; case 2: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 30) * 3.20f) + 4; break; case 3: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 48) * 2.05f) + 2; break; case 4: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 65) * 1.50f) + 2; break; case 6: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 87) * 1.20f) - 4; break; case 7: chance = static_cast<uint32_t>(std::min<uint32_t>(skill, 90) * 1.10f) + 1; break; default: chance = it.hitChance; break; } } else { chance = maxHitChance; } } else { chance = it.hitChance; } if (item->getWeaponType() == WEAPON_AMMO) { Item* bow = player->getWeapon(true); if (bow && bow->getHitChance() != 0) { chance += bow->getHitChance(); } } if (chance >= uniform_random(1, 100)) { Weapon::internalUseWeapon(player, item, target, damageModifier); } else { //miss target Tile* destTile = target->getTile(); if (!Position::areInRange<1, 1, 0>(player->getPosition(), target->getPosition())) { static std::vector<std::pair<int32_t, int32_t>> destList { {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1} }; std::shuffle(destList.begin(), destList.end(), getRandomGenerator()); Position destPos = target->getPosition(); for (const auto& dir : destList) { // Blocking tiles or tiles without ground ain't valid targets for spears Tile* tmpTile = g_game.map.getTile(destPos.x + dir.first, destPos.y + dir.second, destPos.z); if (tmpTile && !tmpTile->hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID) && tmpTile->ground != nullptr) { destTile = tmpTile; break; } } } Weapon::internalUseWeapon(player, item, destTile); } return true; }
void OSGTerrainEngineNode::addImageLayer( ImageLayer* layerAdded ) { if ( !layerAdded || !layerAdded->getTileSource() ) return; // visit all existing terrain tiles and inform each one of the new image layer: TileVector tiles; _terrain->getTiles( tiles ); for( TileVector::iterator itr = tiles.begin(); itr != tiles.end(); ++itr ) { Tile* tile = itr->get(); StreamingTile* streamingTile = 0L; GeoImage geoImage; bool needToUpdateImagery = false; int imageLOD = -1; if ( !_isStreaming || tile->getKey().getLevelOfDetail() == 1 ) { // in standard mode, or at the first LOD in seq/pre mode, fetch the image immediately. TileKey geoImageKey = tile->getKey(); _tileFactory->createValidGeoImage( layerAdded, tile->getKey(), geoImage, geoImageKey ); imageLOD = tile->getKey().getLevelOfDetail(); } else { // in seq/pre mode, set up a placeholder and mark the tile as dirty. geoImage = GeoImage(ImageUtils::createEmptyImage(), tile->getKey().getExtent() ); needToUpdateImagery = true; streamingTile = static_cast<StreamingTile*>(tile); } if (geoImage.valid()) { const MapInfo& mapInfo = _update_mapf->getMapInfo(); double img_min_lon, img_min_lat, img_max_lon, img_max_lat; geoImage.getExtent().getBounds(img_min_lon, img_min_lat, img_max_lon, img_max_lat); //Specify a new locator for the color with the coordinates of the TileKey that was actually used to create the image osg::ref_ptr<GeoLocator> img_locator = tile->getKey().getProfile()->getSRS()->createLocator( img_min_lon, img_min_lat, img_max_lon, img_max_lat, !mapInfo.isGeocentric() ); //Set the CS to geocentric if we are dealing with a geocentric map if ( mapInfo.isGeocentric() ) { img_locator->setCoordinateSystemType( osgTerrain::Locator::GEOCENTRIC ); } tile->setCustomColorLayer( CustomColorLayer( layerAdded, geoImage.getImage(), img_locator.get(), imageLOD, tile->getKey() ) ); // if necessary, tell the tile to queue up a new imagery request (since we // just installed a placeholder) if ( needToUpdateImagery ) { streamingTile->updateImagery( layerAdded, *_update_mapf, _tileFactory.get() ); } } else { // this can happen if there's no data in the new layer for the given tile. // we will rely on the driver to dump out a warning if this is an error. } tile->applyImmediateTileUpdate( TileUpdate::ADD_IMAGE_LAYER, layerAdded->getUID() ); } updateTextureCombining(); }
bool C3Sav::Impl::loadCity( std::fstream& f, Game& game ) { uint32_t tmp; // need to rewrite better std::vector<short int> graphicGrid; graphicGrid.resize( 26244, 0 ); std::vector<unsigned char> edgeGrid; edgeGrid.resize( 26244, 0 ); std::vector<short int> terrainGrid; terrainGrid.resize( 26244, 0 ); std::vector<unsigned char> rndmTerGrid; rndmTerGrid.resize(26244, 0); std::vector<unsigned char> randomGrid; randomGrid.resize( 26244, 0 ); std::vector<unsigned char> zeroGrid; zeroGrid.resize( 26244, 0 ); if( !f.is_open() ) { Logger::warning( "GameLoaderC3Sav: can't open file " ); return false; } f.read( (char*)&tmp, 4); // read dummy std::string cityName = LoaderHelper::getDefaultCityName( tmp ); game.city()->setName( cityName ); f.read((char*)&tmp, 4); // read scenario flag try { f.read((char*)&tmp, 4); // read length of compressed chunk Logger::warning( "GameLoaderC3Sav: length of compressed ids is %d", tmp ); PKWareInputStream *pk = new PKWareInputStream(&f, false, tmp); for (int i = 0; i < 162 * 162; i++) { graphicGrid[i] = pk->readShort(); } pk->empty(); delete pk; f.read((char*)&tmp, 4); // read length of compressed chunk Logger::warning( "GameLoaderC3Sav: length of compressed egdes is %d", tmp ); pk = new PKWareInputStream(&f, false, tmp); for (int i = 0; i < 162 * 162; i++) { edgeGrid[i] = pk->readByte(); } pk->empty(); delete pk; SkipCompressed(f); // skip building ids f.read((char*)&tmp, 4); // read length of compressed chunk Logger::warning( "GameLoaderC3Sav: length of compressed terraindata is %d", tmp ); pk = new PKWareInputStream(&f, false, tmp); for (int i = 0; i < 162 * 162; i++) { terrainGrid[i] = pk->readShort(); } pk->empty(); delete pk; SkipCompressed(f); SkipCompressed(f); SkipCompressed(f); SkipCompressed(f); f.read((char*)&randomGrid[0], 26244); SkipCompressed(f); SkipCompressed(f); SkipCompressed(f); SkipCompressed(f); SkipCompressed(f); // here goes walkers array f.read((char*)&tmp, 4); // read length of compressed chunk Logger::warning( "GameLoaderC3Sav: length of compressed walkers data is %d", tmp ); pk = new PKWareInputStream(&f, false, tmp); for (int j = 0; j < 1000; j++) { pk->skip(10); pk->readShort(); pk->skip(8); pk->readByte(); pk->readByte(); pk->skip(106); } pk->empty(); delete pk; int length; f.read((char*)&length, 4); // read next length :-) if (length <= 0) f.seekg(1200, std::ios::cur); else f.seekg(length, std::ios::cur); SkipCompressed(f); SkipCompressed(f); // 3x int f.read((char*)&tmp, 4); f.read((char*)&tmp, 4); f.read((char*)&tmp, 4); SkipCompressed(f); f.seekg(70, std::ios::cur); SkipCompressed(f); // skip building list f.seekg(208, std::ios::cur); SkipCompressed(f); // skip unknown f.seekg(788, std::ios::cur); // skip unused data f.read((char*)&tmp, 4); //mapsize int size = tmp; PlayerCityPtr oCity = game.city(); Tilemap& oTilemap = oCity->tilemap(); oCity->resize(size); oCity->setCameraPos( TilePos( 0, 0 ) ); initEntryExit( f, game.city() ); f.seekg(1312, std::ios::cur); char climate; f.read(&climate, 1); oCity->setClimate((ClimateType)climate); // here goes the WORK! // loads the graphics map int border_size = (162 - size) / 2; std::map< int, std::map< int, unsigned char > > edgeData; game.city()->setCameraPos( TilePos( size/2, size/2 ) ); for (int itA = 0; itA < size; ++itA) { for (int itB = 0; itB < size; ++itB) { int i = itB; int j = size - itA - 1; int index = 162 * (border_size + itA) + border_size + itB; Tile& tile = oTilemap.at(i, j); unsigned int imgId = graphicGrid[index]; Picture pic = imgid::toPicture( imgId ); if( pic.isValid() ) { tile.setPicture( pic ); tile.setOriginalImgId( imgId ); } else { TileOverlay::Type ovType = LoaderHelper::convImgId2ovrType( imgId ); if( ovType == constants::objects::unknown ) { Logger::warning( "!!! GameLoaderC3Sav: Unknown building %x at [%d,%d]", imgId, i, j ); } baseBuildings[ tile.pos() ] = imgId; pic = Picture::load( ResourceGroup::land1a, 230 + math::random( 57 ) ); tile.setPicture( pic ); tile.setOriginalImgId( imgid::fromResource( pic.name() ) ); } edgeData[ i ][ j ] = edgeGrid[index]; tile::decode( tile, terrainGrid[index] ); tile::fixPlateauFlags( tile ); } } for (int i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) { unsigned char ed = edgeData[ i][ j ]; if( ed == 0x00) { int size = 1; { int dj; try { // find size, 5 is maximal size for building for (dj = 0; dj < 5; ++dj) { int edd = edgeData[ i ][ j - dj ]; // find bottom left corner if (edd == 8 * dj + 0x40) { size = dj + 1; break; } } } catch(...) { size = dj + 1; } } Tile& master = oTilemap.at(i, j - size + 1); //Logger::warning( "Master will be at (%d,%d)", master.i(), master.j() ); for (int di = 0; di < size; ++di) { for (int dj = 0; dj < size; ++dj) { oTilemap.at(master.i() + di, master.j() + dj).setMasterTile(&master); } } } // Check if it is building and type of building //if (ttile.getMasterTile() == NULL) std::map<TilePos, unsigned int>::iterator bbIt = baseBuildings.find( TilePos( i, j ) ); unsigned int bbImgId = bbIt == baseBuildings.end() ? 0 : bbIt->second; Tile& tile = oTilemap.at( i, j ); Tile* masterTile = tile.masterTile(); if( !masterTile ) masterTile = &tile; if( masterTile->overlay().isNull() ) { LoaderHelper::decodeTerrain( *masterTile, oCity, bbImgId ); } } } } catch(PKException) { THROW("fatal error when unpacking"); } return true; }
void River::initTerrain(Tile& terrain) { terrain.setFlag( Tile::clearAll, true ); terrain.setFlag( Tile::tlWater, true ); }
bool IOMapSerialize::loadItems(Database* db, DBResult* result, Cylinder* parent, bool depotTransfer/* = false*/) { ItemMap itemMap; Tile* tile = NULL; if(!parent->getItem()) tile = parent->getTile(); Item* item = NULL; int32_t sid, pid, id, count; do { sid = result->getDataInt("sid"); pid = result->getDataInt("pid"); id = result->getDataInt("itemtype"); count = result->getDataInt("count"); item = NULL; uint64_t attrSize = 0; const char* attr = result->getDataStream("attributes", attrSize); PropStream propStream; propStream.init(attr, attrSize); const ItemType& iType = Item::items[id]; if(iType.moveable || iType.forceSerialize || pid) { if(!(item = Item::CreateItem(id, count))) continue; if(item->unserializeAttr(propStream)) { if(!pid) { parent->__internalAddThing(item); item->__startDecaying(); } } else std::cout << "[Warning - IOMapSerialize::loadItems] Unserialization error [0] for item type " << id << std::endl; } else if(tile) { //find this type in the tile Item* findItem = NULL; for(uint32_t i = 0; i < tile->getThingCount(); ++i) { if(!(findItem = tile->__getThing(i)->getItem())) continue; if(findItem->getID() == id) { item = findItem; break; } if(iType.isDoor() && findItem->getDoor()) { item = findItem; break; } if(iType.isBed() && findItem->getBed()) { item = findItem; break; } } } if(item) { if(item->unserializeAttr(propStream)) { if((item = g_game.transformItem(item, id))) itemMap[sid] = std::make_pair(item, pid); } else std::cout << "[Warning - IOMapSerialize::loadItems] Unserialization error [1] for item type " << id << std::endl; } else if((item = Item::CreateItem(id))) { item->unserializeAttr(propStream); if(!depotTransfer) std::cout << "[Warning - IOMapSerialize::loadItems] NULL item at " << tile->getPosition() << " (type = " << id << ", sid = " << sid << ", pid = " << pid << ")" << std::endl; else itemMap[sid] = std::make_pair(parent->getItem(), pid); delete item; item = NULL; } } while(result->next()); ItemMap::iterator it; for(ItemMap::reverse_iterator rit = itemMap.rbegin(); rit != itemMap.rend(); ++rit) { if(!(item = rit->second.first)) continue; int32_t pid = rit->second.second; it = itemMap.find(pid); if(it == itemMap.end()) continue; if(Container* container = it->second.first->getContainer()) { container->__internalAddThing(item); g_game.startDecay(item); } } return true; }
/** * Calculates the effects of the explosion. */ void ExplosionBState::explode() { bool terrainExplosion = false; SavedBattleGame *save = _parent->getSave(); // after the animation is done, the real explosion/hit takes place if (_item) { if (!_unit && _item->getPreviousOwner()) { _unit = _item->getPreviousOwner(); } BattleUnit *victim = 0; if (_areaOfEffect) { save->getTileEngine()->explode(_center, _power, _item->getRules()->getDamageType(), _item->getRules()->getExplosionRadius(), _unit); } else if (!_cosmetic) { ItemDamageType type = _item->getRules()->getDamageType(); victim = save->getTileEngine()->hit(_center, _power, type, _unit); } // check if this unit turns others into zombies if (!_item->getRules()->getZombieUnit().empty() && victim && victim->getArmor()->getSize() == 1 && (victim->getGeoscapeSoldier() || victim->getUnitRules()->getRace() == "STR_CIVILIAN") && victim->getSpawnUnit().empty()) { // converts the victim to a zombie on death victim->setRespawn(true); victim->setSpawnUnit(_item->getRules()->getZombieUnit()); } } if (_tile) { ItemDamageType DT; switch (_tile->getExplosiveType()) { case 0: DT = DT_HE; break; case 5: DT = DT_IN; break; case 6: DT = DT_STUN; break; default: DT = DT_SMOKE; break; } if (DT != DT_HE) { _tile->setExplosive(0,0,true); } save->getTileEngine()->explode(_center, _power, DT, _power/10); terrainExplosion = true; } if (!_tile && !_item) { int radius = 6; // explosion not caused by terrain or an item, must be by a unit (cyberdisc) if (_unit && (_unit->getSpecialAbility() == SPECAB_EXPLODEONDEATH || _unit->getSpecialAbility() == SPECAB_BURN_AND_EXPLODE)) { radius = _parent->getMod()->getItem(_unit->getArmor()->getCorpseGeoscape())->getExplosionRadius(); } save->getTileEngine()->explode(_center, _power, DT_HE, radius); terrainExplosion = true; } if (!_cosmetic) { // now check for new casualties _parent->checkForCasualties(_item, _unit, false, terrainExplosion); } // if this explosion was caused by a unit shooting, now it's the time to put the gun down if (_unit && !_unit->isOut() && _lowerWeapon) { _unit->aim(false); _unit->setCache(0); } _parent->getMap()->cacheUnits(); _parent->popState(); // check for terrain explosions Tile *t = save->getTileEngine()->checkForTerrainExplosions(); if (t) { Position p = Position(t->getPosition().x * 16, t->getPosition().y * 16, t->getPosition().z * 24); p += Position(8,8,0); _parent->statePushFront(new ExplosionBState(_parent, p, 0, _unit, t)); } if (_item && (_item->getRules()->getBattleType() == BT_GRENADE || _item->getRules()->getBattleType() == BT_PROXIMITYGRENADE)) { for (std::vector<BattleItem*>::iterator j = _parent->getSave()->getItems()->begin(); j != _parent->getSave()->getItems()->end(); ++j) { if (_item->getId() == (*j)->getId()) { _parent->getSave()->removeItem(_item); break; } } } }
bool IOMapSerialize::loadItem(PropStream& propStream, Cylinder* parent, bool depotTransfer/* = false*/) { Tile* tile = NULL; if(!parent->getItem()) tile = parent->getTile(); uint16_t id = 0; propStream.GET_USHORT(id); Item* item = NULL; const ItemType& iType = Item::items[id]; if(iType.moveable || iType.forceSerialize || (!depotTransfer && !tile)) { if(!(item = Item::CreateItem(id))) return true; if(!item->unserializeAttr(propStream)) { std::cout << "[Warning - IOMapSerialize::loadItem] Unserialization error [0] for item type " << id << std::endl; delete item; return false; } if(Container* container = item->getContainer()) { if(!loadContainer(propStream, container)) { delete item; return false; } } if(parent) { parent->__internalAddThing(item); item->__startDecaying(); } else delete item; return true; } if(tile) { //Stationary items Item* findItem = NULL; for(uint32_t i = 0; i < tile->getThingCount(); ++i) { if(!(findItem = tile->__getThing(i)->getItem())) continue; if(findItem->getID() == id) { item = findItem; break; } if(iType.isDoor() && findItem->getDoor()) { item = findItem; break; } if(iType.isBed() && findItem->getBed()) { item = findItem; break; } } } if(item) { if(item->unserializeAttr(propStream)) { Container* container = item->getContainer(); if(container && !loadContainer(propStream, container)) return false; item = g_game.transformItem(item, id); } else std::cout << "[Warning - IOMapSerialize::loadItem] Unserialization error [1] for item type " << id << std::endl; return true; } //The map changed since the last save, just read the attributes if(!(item = Item::CreateItem(id))) return true; item->unserializeAttr(propStream); if(Container* container = item->getContainer()) { if(!loadContainer(propStream, container)) { delete item; return false; } if(depotTransfer) { for(ItemList::const_iterator it = container->getItems(); it != container->getEnd(); ++it) parent->__addThing(NULL, (*it)); container->itemlist.clear(); } } delete item; return true; }
void updateSpeedMultiplier( const Tile& tile ) { speedMultiplier = (tile.getTerrain().isRoad() || tile.getTerrain().isGarden()) ? 1.f : 0.5f; }
Map* Parseur::doParsing() { Field* fieldLayer; std::vector<ObjectLayers*> layersObjects; xml_node mapXml = doc_.child("map"); int mapWidth = mapXml.attribute("width").as_int(); int mapHeight = mapXml.attribute("height").as_int(); std::string orientation(mapXml.attribute("orientation").value()); //"Header" TMX file parsing (tileset tags) xml_node firstTileSetXml = mapXml.child("tileset"); std::vector<TileSet*> ensTileSet; for(xml_node aTileSet = firstTileSetXml; aTileSet; aTileSet = aTileSet.next_sibling("tileset")) { //create new tileSetImage xml_node tilsetImageXml = aTileSet.child("image"); TileSetImage* tsi = createTileSetImage(tilsetImageXml.attribute("source").value(), tilsetImageXml.attribute("width").as_int(), tilsetImageXml.attribute("height").as_int()); //create new tileSet with given attributs. TileSet* ts = createTileSet(aTileSet.attribute("firstgid").as_int(), aTileSet.attribute("name").value(), aTileSet.attribute("tilewidth").as_int(), aTileSet.attribute("tileheight").as_int(), tsi); //get tile tags xml_node firstTileXml = aTileSet.child("tile"); for(xml_node aTile = firstTileXml; aTile; aTile = aTile.next_sibling("tile")) { //foreach tile tags create new tile Tile* tile = createTile(aTile.attribute("id").as_int(), ts, ts->getNbTilePerRow()); // std::cout << "tileId : " << aTile.attribute("id").as_int() << " :" << std::endl; xml_node firstTileProperty = aTile.child("properties").child("property"); for(xml_node aProperty = firstTileProperty; aProperty; aProperty = aProperty.next_sibling("property")) { //get property tags and add it to tile object char* name; name = new char[strlen(aProperty.attribute("name").value())+1]; strcpy(name, aProperty.attribute("name").value()); char* value; value = new char[strlen(aProperty.attribute("value").value())]; strcpy(value, aProperty.attribute("value").value()); tile->addProperty(name, value); // std::cout << "\t property " << name << " = " << value << std::endl; } ts->addTile(tile); ensTileSet.push_back(ts); } } //parsing layers xml_node firstLayerXml = mapXml.child("layer"); Field* field; int x; int y; for(xml_node aLayer = firstLayerXml; aLayer; aLayer = aLayer.next_sibling("layer")) { // std::cout << aLayer.attribute("name").value() << std::endl; ensCells cellsMap; xml_node firstCellXml = aLayer.child("data").child("tile"); x = 0; y = 0; for(xml_node aCellXml = firstCellXml; aCellXml; aCellXml = aCellXml.next_sibling("tile")) { int gid = aCellXml.attribute("gid").as_int(); //get Tile with the current gid Tile* t; bool get = false; TileSet* currentTileSet; std::vector<TileSet*>::iterator it = ensTileSet.begin(); Obstacle* obstacle; while(it != ensTileSet.end() && !get) { t = (*it)->getTile(gid-(*it)->getFirstGid()); currentTileSet = (*it); if((*t)!=Tile()) { obstacle = mapFactory_->createObstacle(t, t->getTileId(), t->getPropertyValue("type"), t->getProperties()); get = true; // std::cout << t->getTileId() << std::endl; } ++it; } if(!get) { obstacle = new Obstacle(); } //pour créer un obstacle il faut un TileSet, un tileId, le type (Field, object, fixed), les propriété //Pour récupérer les Cells du layers, il faut un Obstacle et la position de la cellule Cell* cell = mapFactory_->createCell(x, y, obstacle); // std::cout << *cell << std::endl; cellsMap.insert(std::pair< std::pair<int, int>, Cell*>(std::pair<int, int>(x,y), cell)); // std::cout << "(" << x << ", " << y << ") : tileId = " << t->getTileId() << std::endl; // //// x++; if(x >= mapWidth) { x=0; y++; } // //normaly, when x=mapWidth and y=mapHeight we have finished to parse this layer } //pour le layer, il faut la taille du layer, et un ensemble de Cell std::string layerName(aLayer.attribute("name").value()); if(layerName.compare("Field")==0) { fieldLayer = mapFactory_->createField(mapWidth, mapHeight, cellsMap); } else if(layerName.compare("Object")==0) { layersObjects.push_back(mapFactory_->createObjectLayers(mapWidth, mapHeight, cellsMap)); } } Map::MAPORIENTATION mapOrient; if(orientation.compare("orthogonal")==0) { mapOrient = Map::MAPORIENTATION_ORTHOGONAL; } else { mapOrient = Map::MAPORIENTATION_ORTHOGONAL; } Map* theMap = mapFactory_->createMap(new Background(), fieldLayer, mapWidth, mapHeight, mapOrient); std::vector<ObjectLayers*>::iterator itm; for(itm = layersObjects.begin(); itm != layersObjects.end(); ++itm) { theMap->addObjectLayers((*itm)); } theMap->addTileSets(ensTileSet); // std::cout << *theMap << std::endl; return theMap; }
/** * Get a widget at a position in the layout. * @param row :: The row of the tile * @param col :: The column of the tile * @return :: A pointer to the MdiSubWindow at this position or NULL if the tile * is empty. */ MdiSubWindow *TiledWindow::getWidget(int row, int col) { Tile *tile = getTile(row, col); return tile->widget(); }
void UnitWalkBState::think() { bool unitspotted = false; // during a walking cycle we make step sounds if (_unit->getStatus() == STATUS_WALKING || _unit->getStatus() == STATUS_FLYING) { if (_unit->getVisible() && _unit->getStatus() == STATUS_WALKING) { // play footstep sound 1 if (_unit->getWalkingPhase() == 3) { Tile *tile = _unit->getTile(); if (tile->getFootstepSound()) { _parent->getGame()->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(22 + (tile->getFootstepSound()*2))->play(); } } // play footstep sound 2 if (_unit->getWalkingPhase() == 7) { Tile *tile = _unit->getTile(); if (tile->getFootstepSound()) { _parent->getGame()->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(23 + (tile->getFootstepSound()*2))->play(); } } } _unit->keepWalking(); // advances the phase // unit moved from one tile to the other, update the tiles if (_unit->getPosition() != _unit->getLastPosition()) { _parent->getGame()->getSavedGame()->getBattleGame()->getTile(_unit->getLastPosition())->setUnit(0); //don't change these _parent->getGame()->getSavedGame()->getBattleGame()->getTile(_unit->getPosition())->setUnit(_unit); //don't change these // if the unit changed level, camera changes level with _parent->getMap()->getCamera()->setViewHeight(_unit->getPosition().z); } // is the step finished? if (_unit->getStatus() == STATUS_STANDING) { _terrain->calculateUnitLighting(); unitspotted = _terrain->calculateFOV(_unit); if (unitspotted) { _pf->abortPath(); if (_unit->getFaction() == FACTION_HOSTILE) { AggroBAIState *aggro = dynamic_cast<AggroBAIState*>(_unit->getCurrentAIState()); if (aggro == 0) { _unit->setAIState(new AggroBAIState(_parent->getGame()->getSavedGame()->getBattleGame(), _unit)); } _parent->handleAI(_unit); } return; } BattleAction action; if (_terrain->checkReactionFire(_unit, &action)) { _parent->statePushBack(new ProjectileFlyBState(_parent, action)); // unit got fired upon - stop walking _pf->abortPath(); return; } } else { // make sure the unit sprites are up to date _parent->getMap()->cacheUnit(_unit); } } // we are just standing around, shouldn't we be walking? if (_unit->getStatus() == STATUS_STANDING) { if (_unit->getVisible()) { setNormalWalkSpeed(); } else { _parent->setStateInterval(1); } int dir = _pf->getStartDirection(); if (dir != -1) { Position destination; int tu = _pf->getTUCost(_unit->getPosition(), dir, &destination, _unit); // gets tu cost, but also gets the destination position. if (tu > _unit->getTimeUnits() && !_parent->dontSpendTUs()) { _result = "STR_NOT_ENOUGH_TIME_UNITS"; _pf->abortPath(); return; } if (_parent->checkReservedTU(_unit, tu) == false) { _pf->abortPath(); return; } // we are looking in the wrong way, turn first // we are not using the turn state, because turning during walking costs no tu if (dir != _unit->getDirection() && dir < Pathfinding::DIR_UP) { _unit->lookAt(dir); return; } // now open doors (if any) int door = _terrain->unitOpensDoor(_unit); if (door == 3) { return; // don't start walking yet, wait for the ufo door to open } if (door == 0) { _parent->getGame()->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(3)->play(); // normal door } if (door == 1) { _parent->getGame()->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(20)->play(); // ufo door return; // don't start walking yet, wait for the ufo door to open } // now start moving dir = _pf->dequeuePath(); if (_unit->spendTimeUnits(tu, _parent->dontSpendTUs())) { if (_unit->spendEnergy(tu, _parent->dontSpendTUs())) { _unit->startWalking(dir, destination); } else { _result = "STR_NOT_ENOUGH_ENERGY"; _parent->popState(); } } else { _result = "STR_NOT_ENOUGH_TIME_UNITS"; _parent->popState(); } // make sure the unit sprites are up to date _parent->getMap()->cacheUnit(_unit); } else { postPathProcedures(); return; } } // turning during walking costs no tu if (_unit->getStatus() == STATUS_TURNING) { _unit->turn(); unitspotted = _terrain->calculateFOV(_unit); // make sure the unit sprites are up to date _parent->getMap()->cacheUnit(_unit); if (unitspotted) { _pf->abortPath(); return; } } }