decider 2 start
19
.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
build
|
||||||
|
logs
|
||||||
|
project/project
|
||||||
|
project/target
|
||||||
|
target
|
||||||
|
tmp
|
||||||
|
.history
|
||||||
|
dist
|
||||||
|
/.idea
|
||||||
|
/*.iml
|
||||||
|
/out
|
||||||
|
/.idea_modules
|
||||||
|
/.classpath
|
||||||
|
/.gradle
|
||||||
|
/.project
|
||||||
|
/RUNNING_PID
|
||||||
|
/.settings
|
||||||
|
/project/*-shim.sbt
|
||||||
|
/activator-sbt-*-shim.sbt
|
||||||
77
app/actors/LobbieActor.scala
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package actors
|
||||||
|
|
||||||
|
import akka.actor.{Actor, ActorLogging, ActorRef}
|
||||||
|
import akka.event.LoggingReceive
|
||||||
|
import com.typesafe.scalalogging.LazyLogging
|
||||||
|
|
||||||
|
import scala.collection.immutable.{HashSet, Queue}
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
case class DeciderMap(map: String, isBanned: Boolean = false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* There is one StockActor per stock symbol. The StockActor maintains a list of users watching the stock and the stock
|
||||||
|
* values. Each StockActor updates a rolling dataset of randomly generated stock values.
|
||||||
|
*/
|
||||||
|
class LobbieActor(lobbyName: String, hostUser: ActorRef) extends Actor with LazyLogging {
|
||||||
|
|
||||||
|
private val name: String = lobbyName
|
||||||
|
|
||||||
|
// user actors
|
||||||
|
protected[this] var users: HashSet[ActorRef] = HashSet.empty[ActorRef]
|
||||||
|
|
||||||
|
private var status = NotStarted
|
||||||
|
|
||||||
|
private var maps: List[DeciderMap] = List(DeciderMap("map1"), DeciderMap("map2"), DeciderMap("map3"))
|
||||||
|
|
||||||
|
private var secondPlayer: Option[ActorRef] = None
|
||||||
|
|
||||||
|
logger.info(s"Create lobby with name $lobbyName")
|
||||||
|
|
||||||
|
|
||||||
|
def receive = LoggingReceive {
|
||||||
|
case BanMap(mapName: String) =>
|
||||||
|
// notify watchers
|
||||||
|
logger.info(s"Ban map $mapName by ${sender.path.name}")
|
||||||
|
users.foreach(_ ! MapsUpdate( maps))
|
||||||
|
case JoinLobbyAsPlayer(_) =>
|
||||||
|
secondPlayer = Some(sender)
|
||||||
|
case WatchLobby(_) =>
|
||||||
|
// add the watcher to the list
|
||||||
|
users = users + sender
|
||||||
|
case LeaveLobby =>
|
||||||
|
users = users - sender
|
||||||
|
if(secondPlayer.contains(sender)) secondPlayer = None
|
||||||
|
if (users.isEmpty) {
|
||||||
|
logger.info(s"Stop lobby with name: $name")
|
||||||
|
context.stop(self)
|
||||||
|
}
|
||||||
|
case InfoQuery =>
|
||||||
|
sender ! LobbyInfoResponse(name, self.path.name, status.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case class BanMap(mapName: String)
|
||||||
|
|
||||||
|
case class MapsUpdate(maps: List[DeciderMap])
|
||||||
|
|
||||||
|
case class MapsHistory(symbol: String, maps: List[DeciderMap])
|
||||||
|
|
||||||
|
case class CreateLobby(userName: String)
|
||||||
|
|
||||||
|
case class JoinLobbyAsPlayer(lobbyName: String)
|
||||||
|
|
||||||
|
case class WatchLobby(lobbyName: String)
|
||||||
|
|
||||||
|
case class LeaveLobby(lobbyName: String)
|
||||||
|
|
||||||
|
case object InfoQuery
|
||||||
|
|
||||||
|
case class LobbyInfoResponse(lobbyName: String, lobbyActorName: String, status: String)
|
||||||
|
|
||||||
|
class LobbyStatus
|
||||||
|
|
||||||
|
sealed case class NotStarted() extends LobbyStatus
|
||||||
|
sealed case class Draft() extends LobbyStatus
|
||||||
|
sealed case class Finish() extends LobbyStatus
|
||||||
48
app/actors/LobbiesActor.scala
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package actors
|
||||||
|
|
||||||
|
import akka.actor.{Actor, ActorLogging, Props}
|
||||||
|
import akka.event.LoggingReceive
|
||||||
|
import akka.pattern.ask
|
||||||
|
import akka.util.Timeout
|
||||||
|
import com.typesafe.scalalogging.LazyLogging
|
||||||
|
|
||||||
|
import scala.collection.mutable.ListBuffer
|
||||||
|
import scala.concurrent.Await
|
||||||
|
import scala.concurrent.duration.DurationInt
|
||||||
|
|
||||||
|
class LobbiesActor extends Actor with LazyLogging {
|
||||||
|
|
||||||
|
implicit val timeout: Timeout = 1.second
|
||||||
|
|
||||||
|
val lobbies: ListBuffer[String] = ListBuffer()
|
||||||
|
|
||||||
|
def receive = LoggingReceive {
|
||||||
|
case CreateLobby(userName) =>
|
||||||
|
val lobbyActor = context.actorOf(Props(new LobbieActor(userName, sender)),
|
||||||
|
s"lobbyActor-${(math.random*100000000L).toLong}")
|
||||||
|
lobbyActor.tell(WatchLobby("watchIt"), sender)
|
||||||
|
case watchLobby@WatchLobby(lobbyName) =>
|
||||||
|
// get or create the StockActor for the symbol and forward this message
|
||||||
|
context.child(lobbyName) match {
|
||||||
|
case Some(lobbyActor) => lobbyActor forward watchLobby
|
||||||
|
case None => logger.error(s"Can't watch lobby $lobbyName - lobby not exists")
|
||||||
|
}
|
||||||
|
case unwatchLobby@LeaveLobby(symbol) =>
|
||||||
|
// if there is a StockActor for the symbol forward this message
|
||||||
|
context.child(symbol).foreach(_.forward(unwatchLobby))
|
||||||
|
case banMap@BanMap(map) =>
|
||||||
|
logger.info(s"forvard ban $map")
|
||||||
|
context.children.foreach(_.forward(banMap))
|
||||||
|
case UnWatchAllLobbies =>
|
||||||
|
context.children.foreach( _.tell(LeaveLobby, sender))
|
||||||
|
case GetAllLobbies =>
|
||||||
|
sender ! context.children.toList.map(lobbyActor =>
|
||||||
|
Await.result(lobbyActor ? InfoQuery, 1.second))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
case object GetAllLobbies
|
||||||
|
|
||||||
|
case object UnWatchAllLobbies
|
||||||
145
app/actors/UserActor.scala
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
package actors
|
||||||
|
|
||||||
|
import actors.UserActor.GetName
|
||||||
|
import akka.actor._
|
||||||
|
import akka.event.LoggingReceive
|
||||||
|
import akka.pattern.ask
|
||||||
|
import akka.util.Timeout
|
||||||
|
import com.typesafe.scalalogging.LazyLogging
|
||||||
|
import play.api.libs.json._
|
||||||
|
|
||||||
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
import scala.concurrent.duration.DurationInt
|
||||||
|
import scala.util.{Failure, Success}
|
||||||
|
|
||||||
|
class UserActor(out: ActorRef,
|
||||||
|
userParentActor: ActorRef,
|
||||||
|
lobbiesActor: ActorRef) extends Actor with LazyLogging {
|
||||||
|
|
||||||
|
implicit val timeout: Timeout = 3.seconds
|
||||||
|
|
||||||
|
var userStatus: UserStatus = InLobby()
|
||||||
|
|
||||||
|
implicit val lobbyResponseWrites: Writes[List[LobbyInfoResponse]] = new Writes[List[LobbyInfoResponse]] {
|
||||||
|
|
||||||
|
implicit val lobbyWrites: OWrites[LobbyInfoResponse] = Json.writes[LobbyInfoResponse]
|
||||||
|
|
||||||
|
override def writes(o: List[LobbyInfoResponse]): JsValue = {
|
||||||
|
JsArray(o.map(lobby => Json.toJson(lobby)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit val mapJson: Writes[DeciderMap] = new Writes[DeciderMap] {
|
||||||
|
def writes(deciderMap: DeciderMap): JsValue = {
|
||||||
|
Json.obj(
|
||||||
|
"map" -> deciderMap.map,
|
||||||
|
"isBanned" -> deciderMap.isBanned
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var name = ""
|
||||||
|
|
||||||
|
override def preStart(): Unit = {
|
||||||
|
super.preStart()
|
||||||
|
|
||||||
|
configureDefaultStocks()
|
||||||
|
}
|
||||||
|
|
||||||
|
def configureDefaultStocks(): Unit = {
|
||||||
|
logger.info(s"Creating user actor")
|
||||||
|
}
|
||||||
|
|
||||||
|
override def receive: Receive = LoggingReceive {
|
||||||
|
|
||||||
|
case MapsUpdate(deciderMaps) =>
|
||||||
|
val maps = deciderMaps.map(map => Json.toJson(map))
|
||||||
|
out ! Json.obj("type" -> "maps", "deciderMaps" -> maps)
|
||||||
|
case GetName =>
|
||||||
|
sender ! name
|
||||||
|
|
||||||
|
case json: JsValue =>
|
||||||
|
// When the user types in a stock in the upper right corner, this is triggered
|
||||||
|
|
||||||
|
val comType = (json \ "type").asOpt[String]
|
||||||
|
comType match {
|
||||||
|
case Some("userName") =>
|
||||||
|
name = (json \ "name").as[String]
|
||||||
|
logger.debug(s"Set user name: $name for actor ${this.self}")
|
||||||
|
case Some("getAllUsers") =>
|
||||||
|
val usersActorFuture = (userParentActor ? UserParentActor.GetAllUsers).mapTo[Iterable[ActorRef]]
|
||||||
|
usersActorFuture.map(actorRefs => {
|
||||||
|
logger.debug(s"There are ${actorRefs.size} users on site")
|
||||||
|
actorRefs.map(userActorRef => userActorRef ? GetName).map(res => {
|
||||||
|
res.onComplete {
|
||||||
|
case Success(name) => logger.debug(s"There is $name on site")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
case Some("createDecider") =>
|
||||||
|
lobbiesActor ! CreateLobby(name)
|
||||||
|
|
||||||
|
case Some("leaveDecider") =>
|
||||||
|
lobbiesActor ! LeaveLobby(name)
|
||||||
|
|
||||||
|
case Some("updateDecider") =>
|
||||||
|
lobbiesActor ! BanMap("map1")
|
||||||
|
|
||||||
|
case Some("getLobbies") =>
|
||||||
|
logger.debug("Get all lobby request")
|
||||||
|
(lobbiesActor ? GetAllLobbies).mapTo[List[LobbyInfoResponse]] onComplete {
|
||||||
|
case Success(lobbies) => {
|
||||||
|
logger.info(s"Received lobbies: $lobbies")
|
||||||
|
out ! Json.obj("type" -> "lobbies", "lobbies" -> lobbies)
|
||||||
|
}
|
||||||
|
case Failure(ex) => logger.error("Received error", ex)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserParentActor(actorSystem: ActorSystem) extends Actor with ActorLogging {
|
||||||
|
|
||||||
|
import UserParentActor._
|
||||||
|
|
||||||
|
override def receive: Receive = LoggingReceive {
|
||||||
|
case Create(id, out, lobbiesActor) =>
|
||||||
|
val child: ActorRef = actorSystem.actorOf(Props(classOf[UserActor], out, self, lobbiesActor), s"userActor-$id")
|
||||||
|
sender() ! child
|
||||||
|
case GetAllUsers =>
|
||||||
|
sender() ! context.children
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserStatus
|
||||||
|
|
||||||
|
case class InLobby() extends UserStatus
|
||||||
|
|
||||||
|
case class NotReady() extends UserStatus
|
||||||
|
|
||||||
|
case class Ready() extends UserStatus
|
||||||
|
|
||||||
|
|
||||||
|
object UserParentActor {
|
||||||
|
|
||||||
|
case class Create(id: String, out: ActorRef, lobbiesActor: ActorRef)
|
||||||
|
|
||||||
|
case object GetAllUsers
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object UserActor {
|
||||||
|
|
||||||
|
trait Factory {
|
||||||
|
// Corresponds to the @Assisted parameters defined in the constructor
|
||||||
|
def apply(out: ActorRef): Actor
|
||||||
|
}
|
||||||
|
|
||||||
|
case object GetName
|
||||||
|
|
||||||
|
case object CreateLobby
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
BIN
app/assets/images/maps/2p_abandon_all_hope.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/assets/images/maps/2p_absolute_zero.jpg
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
app/assets/images/maps/2p_antiga_bay.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
app/assets/images/maps/2p_battle_marshes.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
app/assets/images/maps/2p_blood_river.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/2p_blood_river_remix.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
app/assets/images/maps/2p_bloody hell.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/assets/images/maps/2p_bloody_hell.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/assets/images/maps/2p_bridge_too_far.jpg
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
app/assets/images/maps/2p_colosseum.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/2p_colosseum_suicide.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/assets/images/maps/2p_colosseum_suicide_pro.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/2p_deadly_fun_archeology.jpg
Normal file
|
After Width: | Height: | Size: 274 KiB |
BIN
app/assets/images/maps/2p_deadmans_crossing.jpg
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
app/assets/images/maps/2p_edemus_gamble.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/2p_eden.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/assets/images/maps/2p_emerald_river.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/assets/images/maps/2p_emperors_valley.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/assets/images/maps/2p_faceoff.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/2p_fallen_city.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/2p_fata_morgana.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/2p_fear.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/2p_fraziersdemise.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
app/assets/images/maps/2p_frostbite_river.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/2p_galenas_crusade.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/assets/images/maps/2p_haines_demise.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
app/assets/images/maps/2p_hellfire_canyon.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/assets/images/maps/2p_jungle_morning.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
app/assets/images/maps/2p_light_brigade.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/assets/images/maps/2p_light_brigade_pro.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/2p_meeting_of_minds.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/2p_meeting_of_minds_pro.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/2p_meeting_of_minds_pro_5p.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/2p_meeting_of_minds_pro_lis.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/2p_moonbase.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
app/assets/images/maps/2p_outer_reaches.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/2p_quests_triumph.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
app/assets/images/maps/2p_quests_triumph_pro.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/assets/images/maps/2p_railway.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
app/assets/images/maps/2p_river_bed.jpg
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
app/assets/images/maps/2p_short_below_zero.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/assets/images/maps/2p_shrine_of_excellion.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
app/assets/images/maps/2p_shrine_of_excellion_[Rem].jpg
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
app/assets/images/maps/2p_sugaroasis.jpg
Normal file
|
After Width: | Height: | Size: 288 KiB |
BIN
app/assets/images/maps/2p_tainted_pair.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/2p_tazins_folly.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/2p_tiboraxx.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/assets/images/maps/2p_titan_fall.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/assets/images/maps/2p_titan_fall_[Rem].jpg
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
app/assets/images/maps/2p_tower_ruins.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/2p_tranquilitys_end.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
app/assets/images/maps/2p_tranquilitys_end_[rem].jpg
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
app/assets/images/maps/2p_tranquilitys_end_pro.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/2p_valley_of_khorne.jpg
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
app/assets/images/maps/2p_velvet_duress.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/assets/images/maps/2p_vile_reef.jpg
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
app/assets/images/maps/2p_volatile_ground.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/2p_vortex_plateau.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
app/assets/images/maps/3p_coral_reef.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/3p_faded_dreams.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/3p_fortress.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/assets/images/maps/3p_heat_wave.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/4p_antiga_bay.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/assets/images/maps/4p_ariel_highlands.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
app/assets/images/maps/4p_biffys_peril.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/assets/images/maps/4p_boramus.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/4p_broken_lands.jpg
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
app/assets/images/maps/4p_cape_of_despair.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/assets/images/maps/4p_cold_war.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/4p_colosseum_of_deadman.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/4p_doom_spiral.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
app/assets/images/maps/4p_dread_peak.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
app/assets/images/maps/4p_eres_badlands.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/assets/images/maps/4p_forgotten_isles.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
app/assets/images/maps/4p_gorhael_crater.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/4p_gurmuns_pass.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
app/assets/images/maps/4p_ice_flow.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/assets/images/maps/4p_into_the_breach.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/4p_janus_savannah.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/assets/images/maps/4p_janus_savannah_pro.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/assets/images/maps/4p_lost_relic.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
app/assets/images/maps/4p_marconia.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
app/assets/images/maps/4p_mariza.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/4p_mountain_trail-1.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/4p_mountain_trail.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/assets/images/maps/4p_murad_swamplands.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
app/assets/images/maps/4p_oderas valley.jpg
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
app/assets/images/maps/4p_oderas_valley.jpg
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
app/assets/images/maps/4p_panrea_lowlands.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
app/assets/images/maps/4p_quatra.jpg
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
app/assets/images/maps/4p_refinery.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/assets/images/maps/4p_rokclaw_foothills.jpg
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
app/assets/images/maps/4p_sad_place.jpg
Normal file
|
After Width: | Height: | Size: 254 KiB |
BIN
app/assets/images/maps/4p_saints_square.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |