Compare commits
10 Commits
a4a74f5c6f
...
bda5a53bca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bda5a53bca | ||
|
|
b0dfc5b67a | ||
|
|
ecc69cd7d3 | ||
|
|
31ce4b7beb | ||
|
|
dc228d82be | ||
|
|
750ea483b6 | ||
|
|
d3e90fb01e | ||
|
|
aa692419cf | ||
|
|
52baef061b | ||
|
|
e71480c1f7 |
19
README.md
@ -1 +1,18 @@
|
|||||||
This is decider for Soulstorm
|
#Десайдер для турниров по Soulstorm
|
||||||
|
|
||||||
|
##Стек технологий backend:
|
||||||
|
|
||||||
|
- akka (не типизированные акторы)
|
||||||
|
- play framework 2.8.2
|
||||||
|
- scala 2.12.8
|
||||||
|
|
||||||
|
##Стек технологий frontend:
|
||||||
|
|
||||||
|
- jquery 1.4.1
|
||||||
|
- верстка/ui: bootstrap 3.3.6
|
||||||
|
|
||||||
|
Для запуска проекта необходимо установить sbt(scala build tools) и выполнить команду ```sbt run```.
|
||||||
|
Если при переходе на ```http://localhost:9000/decider/classic``` откроется десайдер - всё сделано правильно.
|
||||||
|
|
||||||
|
В проекте предусмотрена защита от xss атак *(хотя, тут воровать то нечего, но всё же)*, потому при развертывании
|
||||||
|
где-либо, необходимо добавить в HomeController в originMatches ip адрес хостинга или домен.
|
||||||
@ -1,26 +1,27 @@
|
|||||||
package actors
|
package actors
|
||||||
|
|
||||||
import actors.UserActor.{BanMapMessage, GetName, HostLeaveLobby, LobbyFatal, Message, RefreshLobbyInfo, SecondPlayerLeaveLobby, SendBanMapMessage, SendMessage, SetUserAsHost, SetUserAsObs, SetUserAsSecondPlayer}
|
import actors.UserActor._
|
||||||
import akka.actor.{Actor, ActorLogging, ActorRef}
|
import akka.actor.{Actor, ActorRef}
|
||||||
import akka.event.LoggingReceive
|
import akka.event.LoggingReceive
|
||||||
import com.typesafe.scalalogging.LazyLogging
|
|
||||||
import akka.pattern.ask
|
|
||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
import com.typesafe.config.{Config, ConfigFactory}
|
import com.typesafe.config.ConfigFactory
|
||||||
|
import com.typesafe.scalalogging.LazyLogging
|
||||||
|
|
||||||
|
import java.util
|
||||||
import scala.collection.JavaConverters.iterableAsScalaIterableConverter
|
import scala.collection.JavaConverters.iterableAsScalaIterableConverter
|
||||||
import scala.collection.immutable.{HashSet, Queue}
|
import scala.collection.immutable.HashSet
|
||||||
import scala.concurrent.Await
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
import scala.util.Try
|
||||||
|
|
||||||
case class LobbyUser(name: String, actorRef: ActorRef)
|
case class LobbyUser(name: String, actorRef: ActorRef)
|
||||||
case class DeciderMap(map: String, var isBanned: Boolean = false)
|
|
||||||
|
case class DeciderMap(map: String, description: Option[String] = None, var isBanned: Boolean = false)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There is one StockActor per stock symbol. The StockActor maintains a list of users watching the stock and the stock
|
* 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.
|
* values. Each StockActor updates a rolling dataset of randomly generated stock values.
|
||||||
*/
|
*/
|
||||||
class LobbieActor(hostUser: LobbyUser) extends Actor with LazyLogging {
|
class LobbieActor(hostUser: LobbyUser, deciderName: String) extends Actor with LazyLogging {
|
||||||
|
|
||||||
val config = ConfigFactory.load()
|
val config = ConfigFactory.load()
|
||||||
logger.info(s"Create lobby... host: ${hostUser.actorRef.path.name}")
|
logger.info(s"Create lobby... host: ${hostUser.actorRef.path.name}")
|
||||||
@ -41,12 +42,17 @@ class LobbieActor(hostUser: LobbyUser) extends Actor with LazyLogging {
|
|||||||
|
|
||||||
private var status: LobbyStatus = NotStarted()
|
private var status: LobbyStatus = NotStarted()
|
||||||
|
|
||||||
private var lobbyType: LobbyType = Last3()
|
private var lobbyType: LobbyType = Last1()
|
||||||
|
|
||||||
|
private var firstPlayerSelectedRaces: Option[SelectedRaces] = None
|
||||||
|
private var secondPlayerSelectedRaces: Option[SelectedRaces] = None
|
||||||
|
|
||||||
|
|
||||||
private val mapsLobby: Set[DeciderMap] = {
|
private val mapsLobby: Set[DeciderMap] = {
|
||||||
val configMaps = config.getStringList("maps").asScala
|
val configMaps = config.getList(s"deciders.$deciderName.maps").asScala
|
||||||
configMaps.map(e => {
|
configMaps.map(e => {
|
||||||
DeciderMap(e)
|
val mapConfig = e.unwrapped().asInstanceOf[util.ArrayList[String]].asScala
|
||||||
|
DeciderMap(mapConfig.head, mapConfig.tail.headOption)
|
||||||
}).toSet
|
}).toSet
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +61,7 @@ class LobbieActor(hostUser: LobbyUser) extends Actor with LazyLogging {
|
|||||||
UserInfo(hostUser.name, firstPlayerReady),
|
UserInfo(hostUser.name, firstPlayerReady),
|
||||||
UserInfo("", secondPlayerReady),
|
UserInfo("", secondPlayerReady),
|
||||||
self.path.name,
|
self.path.name,
|
||||||
|
deciderName,
|
||||||
status.toString(),
|
status.toString(),
|
||||||
playerTurn,
|
playerTurn,
|
||||||
lobbyType.toString(),
|
lobbyType.toString(),
|
||||||
@ -77,18 +84,10 @@ class LobbieActor(hostUser: LobbyUser) extends Actor with LazyLogging {
|
|||||||
if (!map.isBanned) {
|
if (!map.isBanned) {
|
||||||
map.isBanned = true
|
map.isBanned = true
|
||||||
if (playerTurn == 1) playerTurn = 2 else playerTurn = 1
|
if (playerTurn == 1) playerTurn = 2 else playerTurn = 1
|
||||||
if(mapsLobby.count(_.isBanned == false) == 3 && lobbyType == Last3() ||
|
if (isFinish) {
|
||||||
mapsLobby.count(_.isBanned == false) == 4 && lobbyType == Last4() ||
|
|
||||||
mapsLobby.count(_.isBanned == false) == 5 && lobbyType == Last5() ||
|
|
||||||
mapsLobby.count(_.isBanned == false) == 1 && lobbyType == LooserPick()){
|
|
||||||
status = Finish()
|
status = Finish()
|
||||||
}
|
}
|
||||||
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
refreshAndBanMap(mapName)
|
||||||
|
|
||||||
val senderName: String = if (sender == host.actorRef) {
|
|
||||||
host.name
|
|
||||||
} else secondPlayer.get.name
|
|
||||||
users.foreach(_ ! SendBanMapMessage(BanMapMessage(senderName, mapName)))
|
|
||||||
} else {
|
} else {
|
||||||
logger.warn(s"User ban map $mapName, but map already banned")
|
logger.warn(s"User ban map $mapName, but map already banned")
|
||||||
}
|
}
|
||||||
@ -101,6 +100,18 @@ class LobbieActor(hostUser: LobbyUser) extends Actor with LazyLogging {
|
|||||||
} else {
|
} else {
|
||||||
logger.warn(s"Player ${sender.path.name} ban map, but lobby status is '$status' status")
|
logger.warn(s"Player ${sender.path.name} ban map, but lobby status is '$status' status")
|
||||||
}
|
}
|
||||||
|
case selectedRaces: SelectedRaces =>
|
||||||
|
if (sender == host.actorRef) {
|
||||||
|
firstPlayerSelectedRaces = Some(selectedRaces)
|
||||||
|
logger.info(s"First player select $selectedRaces")
|
||||||
|
} else if (sender == secondPlayer.get.actorRef) {
|
||||||
|
secondPlayerSelectedRaces = Some(selectedRaces)
|
||||||
|
logger.info(s"Second player select $selectedRaces")
|
||||||
|
}
|
||||||
|
if (firstPlayerSelectedRaces.nonEmpty && secondPlayerSelectedRaces.nonEmpty) {
|
||||||
|
status = Draft()
|
||||||
|
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
||||||
|
}
|
||||||
case SetReady =>
|
case SetReady =>
|
||||||
// notify watchers
|
// notify watchers
|
||||||
var readyPlayer = sender()
|
var readyPlayer = sender()
|
||||||
@ -111,7 +122,7 @@ class LobbieActor(hostUser: LobbyUser) extends Actor with LazyLogging {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (firstPlayerReady && secondPlayerReady) {
|
if (firstPlayerReady && secondPlayerReady) {
|
||||||
status = Draft()
|
status = SelectRace()
|
||||||
}
|
}
|
||||||
|
|
||||||
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
||||||
@ -128,14 +139,15 @@ class LobbieActor(hostUser: LobbyUser) extends Actor with LazyLogging {
|
|||||||
|
|
||||||
case ChangeLobbyType(lobbyTypeNew) =>
|
case ChangeLobbyType(lobbyTypeNew) =>
|
||||||
lobbyTypeNew match {
|
lobbyTypeNew match {
|
||||||
|
case "last1" =>
|
||||||
|
lobbyType = Last1()
|
||||||
case "last3" =>
|
case "last3" =>
|
||||||
lobbyType = Last3()
|
lobbyType = Last3()
|
||||||
case "last4" =>
|
|
||||||
lobbyType = Last4()
|
|
||||||
case "last5" =>
|
case "last5" =>
|
||||||
lobbyType = Last5()
|
lobbyType = Last5()
|
||||||
case "looserpick" =>
|
case "last7" =>
|
||||||
lobbyType = LooserPick()
|
lobbyType = Last7()
|
||||||
|
|
||||||
}
|
}
|
||||||
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
||||||
|
|
||||||
@ -177,7 +189,7 @@ class LobbieActor(hostUser: LobbyUser) extends Actor with LazyLogging {
|
|||||||
} else if (secondPlayer.exists(_.actorRef == sender())) {
|
} else if (secondPlayer.exists(_.actorRef == sender())) {
|
||||||
secondPlayerReady = false
|
secondPlayerReady = false
|
||||||
secondPlayer = None
|
secondPlayer = None
|
||||||
if(status == Draft()){
|
if (status == Draft() || status == SelectRace()) {
|
||||||
users.foreach(_ ! SecondPlayerLeaveLobby)
|
users.foreach(_ ! SecondPlayerLeaveLobby)
|
||||||
context.stop(self)
|
context.stop(self)
|
||||||
} else {
|
} else {
|
||||||
@ -196,21 +208,38 @@ class LobbieActor(hostUser: LobbyUser) extends Actor with LazyLogging {
|
|||||||
private def getLobbyInfoResponse: LobbyInfo = {
|
private def getLobbyInfoResponse: LobbyInfo = {
|
||||||
val user2Name = secondPlayer.map(_.name).getOrElse("")
|
val user2Name = secondPlayer.map(_.name).getOrElse("")
|
||||||
LobbyInfo(
|
LobbyInfo(
|
||||||
UserInfo(host.name, firstPlayerReady),
|
UserInfo(host.name, firstPlayerReady, firstPlayerSelectedRaces),
|
||||||
UserInfo(user2Name, secondPlayerReady),
|
UserInfo(user2Name, secondPlayerReady, secondPlayerSelectedRaces),
|
||||||
self.path.name,
|
self.path.name,
|
||||||
|
deciderName,
|
||||||
status.toString(),
|
status.toString(),
|
||||||
playerTurn,
|
playerTurn,
|
||||||
lobbyType.toString(),
|
lobbyType.toString(),
|
||||||
mapsLobby)
|
mapsLobby)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def isFinish: Boolean = {
|
||||||
|
mapsLobby.count(_.isBanned == false) == 1 && lobbyType == Last1() ||
|
||||||
|
mapsLobby.count(_.isBanned == false) == 3 && lobbyType == Last3() ||
|
||||||
|
mapsLobby.count(_.isBanned == false) == 5 && lobbyType == Last5() ||
|
||||||
|
mapsLobby.count(_.isBanned == false) == 7 && lobbyType == Last7()
|
||||||
|
}
|
||||||
|
|
||||||
|
private def refreshAndBanMap(mapName: String): Unit = {
|
||||||
|
val senderName: String = if (sender == host.actorRef) {
|
||||||
|
host.name
|
||||||
|
} else secondPlayer.get.name
|
||||||
|
users.foreach(_ ! SendBanMapMessage(BanMapMessage(senderName, mapName)))
|
||||||
|
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case class BanMap(mapName: String)
|
case class BanMap(mapName: String)
|
||||||
|
|
||||||
case class MapsUpdate(maps: Set[String])
|
case class MapsUpdate(maps: Set[String])
|
||||||
|
|
||||||
case class CreateLobby(userName: String)
|
case class CreateLobby(userName: String, deciderName: String)
|
||||||
|
|
||||||
case class JoinLobbyAsPlayer(lobbyUser: LobbyUser)
|
case class JoinLobbyAsPlayer(lobbyUser: LobbyUser)
|
||||||
|
|
||||||
@ -228,13 +257,18 @@ case class MessageForLobby(message: String)
|
|||||||
|
|
||||||
case class ChangeLobbyType(lobbyType: String)
|
case class ChangeLobbyType(lobbyType: String)
|
||||||
|
|
||||||
|
case class ChangeIsNecronSelected(isSelected: Boolean)
|
||||||
|
|
||||||
case object InfoQuery
|
case object InfoQuery
|
||||||
|
|
||||||
case class UserInfo(name: String, isReady: Boolean)
|
case class SelectedRaces(mainRaces: List[Int], additionalRaces: List[Int])
|
||||||
|
|
||||||
|
case class UserInfo(name: String, isReady: Boolean, selectedRaces: Option[SelectedRaces] = None)
|
||||||
|
|
||||||
case class LobbyInfo(user1Info: UserInfo,
|
case class LobbyInfo(user1Info: UserInfo,
|
||||||
user2Info: UserInfo,
|
user2Info: UserInfo,
|
||||||
lobbyActorName: String,
|
lobbyActorName: String,
|
||||||
|
deciderName: String,
|
||||||
status: String,
|
status: String,
|
||||||
playerTurn: BigDecimal,
|
playerTurn: BigDecimal,
|
||||||
selectedType: String,
|
selectedType: String,
|
||||||
@ -243,12 +277,21 @@ case class LobbyInfo(user1Info: UserInfo,
|
|||||||
class LobbyStatus
|
class LobbyStatus
|
||||||
|
|
||||||
sealed case class NotStarted() extends LobbyStatus
|
sealed case class NotStarted() extends LobbyStatus
|
||||||
|
|
||||||
|
sealed case class SelectRace() extends LobbyStatus
|
||||||
|
|
||||||
sealed case class Draft() extends LobbyStatus
|
sealed case class Draft() extends LobbyStatus
|
||||||
|
|
||||||
sealed case class Finish() extends LobbyStatus
|
sealed case class Finish() extends LobbyStatus
|
||||||
|
|
||||||
class LobbyType
|
class LobbyType
|
||||||
|
|
||||||
|
sealed case class Last1() extends LobbyType
|
||||||
|
|
||||||
sealed case class Last3() extends LobbyType
|
sealed case class Last3() extends LobbyType
|
||||||
sealed case class Last4() extends LobbyType
|
|
||||||
sealed case class Last5() extends LobbyType
|
sealed case class Last5() extends LobbyType
|
||||||
sealed case class LooserPick() extends LobbyType
|
|
||||||
|
sealed case class Last7() extends LobbyType
|
||||||
|
|
||||||
|
sealed case class Superfinal() extends LobbyType
|
||||||
|
|||||||
@ -17,10 +17,10 @@ class LobbiesActor extends Actor with LazyLogging {
|
|||||||
val lobbies: ListBuffer[String] = ListBuffer()
|
val lobbies: ListBuffer[String] = ListBuffer()
|
||||||
|
|
||||||
def receive: Receive = LoggingReceive {
|
def receive: Receive = LoggingReceive {
|
||||||
case CreateLobby(hostName) =>
|
case CreateLobby(hostName, deciderName) =>
|
||||||
val hostActorRef = sender
|
val hostActorRef = sender
|
||||||
logger.info(s"Player ${hostActorRef.path.name} create lobby.")
|
logger.info(s"Player ${hostActorRef.path.name} create lobby.")
|
||||||
val lobbyActor = context.actorOf(Props(new LobbieActor(LobbyUser(hostName, hostActorRef))),
|
val lobbyActor = context.actorOf(Props(new LobbieActor(LobbyUser(hostName, hostActorRef), deciderName)),
|
||||||
s"lobbyActor-${(math.random * 100000000L).toLong}")
|
s"lobbyActor-${(math.random * 100000000L).toLong}")
|
||||||
lobbyActor.tell(WatchLobby("watchIt"), hostActorRef)
|
lobbyActor.tell(WatchLobby("watchIt"), hostActorRef)
|
||||||
case JoinLobbyByActorName(lobbyName, userName) =>
|
case JoinLobbyByActorName(lobbyName, userName) =>
|
||||||
|
|||||||
@ -13,21 +13,27 @@ import scala.concurrent.duration.DurationInt
|
|||||||
import scala.util.{Failure, Success}
|
import scala.util.{Failure, Success}
|
||||||
|
|
||||||
class UserActor(out: ActorRef,
|
class UserActor(out: ActorRef,
|
||||||
userParentActor: ActorRef) extends Actor with LazyLogging {
|
userParentActor: ActorRef,
|
||||||
|
ip: String) extends Actor with LazyLogging {
|
||||||
|
|
||||||
implicit val timeout: Timeout = 3.seconds
|
implicit val timeout: Timeout = 3.seconds
|
||||||
|
|
||||||
|
val ipAddress: String = ip
|
||||||
|
|
||||||
var lobbieActor: Option[ActorRef] = None
|
var lobbieActor: Option[ActorRef] = None
|
||||||
|
|
||||||
implicit val mapJson: Writes[DeciderMap] = new Writes[DeciderMap] {
|
implicit val mapJson: Writes[DeciderMap] = new Writes[DeciderMap] {
|
||||||
def writes(deciderMap: DeciderMap): JsValue = {
|
def writes(deciderMap: DeciderMap): JsValue = {
|
||||||
Json.obj(
|
Json.obj(
|
||||||
"map" -> deciderMap.map,
|
"map" -> deciderMap.map,
|
||||||
|
"description" -> deciderMap.description,
|
||||||
"isBanned" -> deciderMap.isBanned
|
"isBanned" -> deciderMap.isBanned
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
implicit val selectedRacesWrites: OWrites[SelectedRaces] = Json.writes[SelectedRaces]
|
||||||
|
|
||||||
implicit val userInfoWrites: OWrites[UserInfo] = Json.writes[UserInfo]
|
implicit val userInfoWrites: OWrites[UserInfo] = Json.writes[UserInfo]
|
||||||
|
|
||||||
implicit val lobbyWrites: Writes[LobbyInfo] = new Writes[LobbyInfo]{
|
implicit val lobbyWrites: Writes[LobbyInfo] = new Writes[LobbyInfo]{
|
||||||
@ -35,6 +41,7 @@ class UserActor(out: ActorRef,
|
|||||||
"user1Info" -> lobby.user1Info,
|
"user1Info" -> lobby.user1Info,
|
||||||
"user2Info" -> lobby.user2Info,
|
"user2Info" -> lobby.user2Info,
|
||||||
"lobbyActorName" -> lobby.lobbyActorName,
|
"lobbyActorName" -> lobby.lobbyActorName,
|
||||||
|
"deciderName" -> lobby.deciderName,
|
||||||
"status" -> lobby.status,
|
"status" -> lobby.status,
|
||||||
"playerTurn" -> lobby.playerTurn,
|
"playerTurn" -> lobby.playerTurn,
|
||||||
"selectedType" -> lobby.selectedType,
|
"selectedType" -> lobby.selectedType,
|
||||||
@ -53,6 +60,7 @@ class UserActor(out: ActorRef,
|
|||||||
"user1Info" -> lobby.user1Info,
|
"user1Info" -> lobby.user1Info,
|
||||||
"user2Info" -> lobby.user2Info,
|
"user2Info" -> lobby.user2Info,
|
||||||
"lobbyActorName" -> lobby.lobbyActorName,
|
"lobbyActorName" -> lobby.lobbyActorName,
|
||||||
|
"deciderName" -> lobby.deciderName,
|
||||||
"status" -> lobby.status,
|
"status" -> lobby.status,
|
||||||
"playerTurn" -> lobby.playerTurn,
|
"playerTurn" -> lobby.playerTurn,
|
||||||
"selectedType" -> lobby.selectedType,
|
"selectedType" -> lobby.selectedType,
|
||||||
@ -127,7 +135,8 @@ class UserActor(out: ActorRef,
|
|||||||
logger.debug(s"Set user name: $name for actor ${this.self}")
|
logger.debug(s"Set user name: $name for actor ${this.self}")
|
||||||
|
|
||||||
case Some("createDecider") =>
|
case Some("createDecider") =>
|
||||||
LobbiesActor.actor ! CreateLobby(name)
|
val deciderName = (json \ "deciderName").as[String]
|
||||||
|
LobbiesActor.actor ! CreateLobby(name, deciderName)
|
||||||
|
|
||||||
case Some("leaveDecider") =>
|
case Some("leaveDecider") =>
|
||||||
lobbieActor.foreach(lobby => lobby ! LeaveLobby)
|
lobbieActor.foreach(lobby => lobby ! LeaveLobby)
|
||||||
@ -163,6 +172,12 @@ class UserActor(out: ActorRef,
|
|||||||
val map = (json \ "map").as[String]
|
val map = (json \ "map").as[String]
|
||||||
lobbieActor.foreach(lobby => lobby ! BanMap(map))
|
lobbieActor.foreach(lobby => lobby ! BanMap(map))
|
||||||
|
|
||||||
|
case Some("selectRace") =>
|
||||||
|
logger.info("RACES: " + json.toString())
|
||||||
|
val races = (json \ "mainRaces").as[List[Int]]
|
||||||
|
val additionalRaces = (json \ "additionalRaces").as[List[Int]]
|
||||||
|
lobbieActor.foreach(lobby => lobby ! SelectedRaces(races, additionalRaces))
|
||||||
|
|
||||||
case Some("getLobbies") =>
|
case Some("getLobbies") =>
|
||||||
logger.debug("Get all lobby request")
|
logger.debug("Get all lobby request")
|
||||||
(LobbiesActor.actor ? GetAllLobbies).mapTo[List[RefreshLobbyInfo]] onComplete {
|
(LobbiesActor.actor ? GetAllLobbies).mapTo[List[RefreshLobbyInfo]] onComplete {
|
||||||
@ -192,10 +207,11 @@ class UserParentActor(actorSystem: ActorSystem) extends Actor with ActorLogging
|
|||||||
import UserParentActor._
|
import UserParentActor._
|
||||||
|
|
||||||
override def receive: Receive = LoggingReceive {
|
override def receive: Receive = LoggingReceive {
|
||||||
case Create(id, out) =>
|
case Create(id, ipAddress, out) =>
|
||||||
val child: ActorRef = actorSystem.actorOf(Props(classOf[UserActor], out, self), s"userActor-$id")
|
val child: ActorRef = actorSystem.actorOf(Props(classOf[UserActor], out, self, ipAddress), s"userActor-$id")
|
||||||
sender() ! child
|
sender() ! child
|
||||||
case GetAllUsers =>
|
case GetAllUsers =>
|
||||||
|
System.out.print("12123" + context.children)
|
||||||
sender() ! context.children
|
sender() ! context.children
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,7 +219,7 @@ class UserParentActor(actorSystem: ActorSystem) extends Actor with ActorLogging
|
|||||||
|
|
||||||
object UserParentActor {
|
object UserParentActor {
|
||||||
|
|
||||||
case class Create(id: String, out: ActorRef)
|
case class Create(id: String, ipAddress: String, out: ActorRef)
|
||||||
|
|
||||||
case object GetAllUsers
|
case object GetAllUsers
|
||||||
|
|
||||||
|
|||||||
BIN
app/assets/images/maps/2p_bloody_hell_[Ed].jpg
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
app/assets/images/maps/2p_marsh_of_rakat.jpg
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
app/assets/images/maps/2p_moonbase_[Ed].jpg
Normal file
|
After Width: | Height: | Size: 230 KiB |
BIN
app/assets/images/maps/2p_winter_confortation.jpg
Normal file
|
After Width: | Height: | Size: 236 KiB |
BIN
app/assets/images/maps/4p_chaos_platenau.jpg
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
app/assets/images/maps/4p_snowblind.jpg
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
app/assets/images/maps/6p_gear.jpg
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
app/assets/images/maps/6p_platform.jpg
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
app/assets/images/maps/6p_snowblind.jpg
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
app/assets/images/maps/8p_glacier.jpg
Normal file
|
After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
BIN
app/assets/images/maps/8p_verdant_isles_ed.jpg
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
app/assets/images/maps/IM_MAP_IM_MAP (1).docx
Normal file
BIN
app/assets/images/maps/IM_MAP_IM_MAP (2).docx
Normal file
BIN
app/assets/images/maps/IM_MAP_IM_MAP.docx
Normal file
@ -132,6 +132,8 @@
|
|||||||
"6p_agamar_desert": "Agamar Desert (6)",
|
"6p_agamar_desert": "Agamar Desert (6)",
|
||||||
"6p_alvarus": "Alvarus (6)",
|
"6p_alvarus": "Alvarus (6)",
|
||||||
"6p_kaurav_city": "Kaurav City (6)",
|
"6p_kaurav_city": "Kaurav City (6)",
|
||||||
|
"6p_snowblind": "Snowblind (6)",
|
||||||
|
"6p_ruined_greatway": "Ruined Greatway (6)",
|
||||||
"8p_forbidden_jungle": "Forbidden Jungle (8)",
|
"8p_forbidden_jungle": "Forbidden Jungle (8)",
|
||||||
"8p_rhean_jungle": "Rhean Jungle (8)",
|
"8p_rhean_jungle": "Rhean Jungle (8)",
|
||||||
"8p_thurabis_plateau": "ThurAbis Plateau (8)",
|
"8p_thurabis_plateau": "ThurAbis Plateau (8)",
|
||||||
|
|||||||
BIN
app/assets/images/maps/img.png
Normal file
|
After Width: | Height: | Size: 565 KiB |
BIN
app/assets/images/maps/img_1.png
Normal file
|
After Width: | Height: | Size: 565 KiB |
BIN
app/assets/images/maps/img_2.png
Normal file
|
After Width: | Height: | Size: 565 KiB |
BIN
app/assets/images/maps/img_3.png
Normal file
|
After Width: | Height: | Size: 502 KiB |
BIN
app/assets/images/maps/img_4.png
Normal file
|
After Width: | Height: | Size: 502 KiB |
BIN
app/assets/images/maps/img_5.png
Normal file
|
After Width: | Height: | Size: 502 KiB |
BIN
app/assets/images/maps/img_6.png
Normal file
|
After Width: | Height: | Size: 499 KiB |
BIN
app/assets/images/maps/винегрет.jpg
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
app/assets/images/maps/гнездо глухаря.jpg
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
app/assets/images/maps/грибная поляна.jpg
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
app/assets/images/maps/из пекинской капусты.jpg
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
app/assets/images/maps/крабовый.jpg
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
app/assets/images/maps/летний.jpg
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
app/assets/images/maps/мимоза.jpg
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
app/assets/images/maps/оливье.jpg
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
app/assets/images/maps/орлиное гнездо.jpg
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
app/assets/images/maps/селедка под шубой.jpg
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
app/assets/images/maps/цезарь.jpg
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
app/assets/images/raceIcons/Chaos.gif
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
app/assets/images/raceIcons/De.gif
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
app/assets/images/raceIcons/Eldar.gif
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
app/assets/images/raceIcons/IG.gif
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
app/assets/images/raceIcons/Nec.gif
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
app/assets/images/raceIcons/Orks.gif
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
app/assets/images/raceIcons/SM.gif
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
app/assets/images/raceIcons/Sob.gif
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
app/assets/images/raceIcons/Tau.gif
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
@ -2,6 +2,12 @@ var ws;
|
|||||||
|
|
||||||
var userName = ""
|
var userName = ""
|
||||||
|
|
||||||
|
var raceCount = $("#raceCount").html()
|
||||||
|
var existAdditionalRaces = $("#existAdditionalRaces").html() === "true"
|
||||||
|
|
||||||
|
var isMuted = false;
|
||||||
|
var isDraftStarted = false;
|
||||||
|
|
||||||
window.onload = function () {
|
window.onload = function () {
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
@ -28,15 +34,12 @@ window.onload = function() {
|
|||||||
"click .title": "check" // Обработчик клика на кнопке "Проверить"
|
"click .title": "check" // Обработчик клика на кнопке "Проверить"
|
||||||
},
|
},
|
||||||
|
|
||||||
joinAsPlayer: function () {
|
|
||||||
this.elCount = "azaz" + getRandomInt(100000000);
|
|
||||||
this.render();
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function () {
|
render: function () {
|
||||||
|
|
||||||
var lobbiesAsTableRows = _.reduce(this.lobbies, function (memo, lobby) {
|
var lobbiesAsTableRows = _.reduce(this.lobbies, function (memo, lobby) {
|
||||||
|
|
||||||
|
if ($("#deciderName").html() !== lobby.deciderName) return memo;
|
||||||
|
|
||||||
var joinButton = (lobby.status === "NotStarted()") ? '<button class="btn btn-primary join-as-player" onclick="joinDecider(\'' + lobby.lobbyActorName + '\')">' +
|
var joinButton = (lobby.status === "NotStarted()") ? '<button class="btn btn-primary join-as-player" onclick="joinDecider(\'' + lobby.lobbyActorName + '\')">' +
|
||||||
'<img src="/assets/images/buttons/isAuto.png" style="height: 25px;"> Join lobby <img src="/assets/images/buttons/isAuto.png" style="height: 25px;">' +
|
'<img src="/assets/images/buttons/isAuto.png" style="height: 25px;"> Join lobby <img src="/assets/images/buttons/isAuto.png" style="height: 25px;">' +
|
||||||
'</button>' : "";
|
'</button>' : "";
|
||||||
@ -76,8 +79,10 @@ window.onload = function() {
|
|||||||
|
|
||||||
$("#createDecider").click(function (event) {
|
$("#createDecider").click(function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
isObserver = false;
|
||||||
ws.send(JSON.stringify({
|
ws.send(JSON.stringify({
|
||||||
type: "createDecider"
|
type: "createDecider",
|
||||||
|
deciderName: $("#deciderName").html()
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -90,6 +95,15 @@ window.onload = function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#mute").click(function (event) {
|
||||||
|
if (isMuted) {
|
||||||
|
isMuted = false;
|
||||||
|
$("#mute").html("🔊");
|
||||||
|
} else {
|
||||||
|
isMuted = true;
|
||||||
|
$("#mute").html("🔈");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$("#exit").click(function (event) {
|
$("#exit").click(function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -101,24 +115,34 @@ window.onload = function() {
|
|||||||
$(".navbar").show();
|
$(".navbar").show();
|
||||||
});
|
});
|
||||||
|
|
||||||
if($.cookie('user')=== undefined){
|
function requestName() {
|
||||||
|
if ($.cookie('user') === undefined || $.cookie('user') === "null" || $.cookie('user') === "") {
|
||||||
var result = prompt("Enter nickname: ",);
|
var result = prompt("Enter nickname: ",);
|
||||||
$.cookie('user', result, {expires: 1337});
|
$.cookie('user', result, {expires: 1337});
|
||||||
userName = result;
|
userName = result;
|
||||||
|
requestName();
|
||||||
} else {
|
} else {
|
||||||
userName = $.cookie('user');
|
userName = $.cookie('user');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestName();
|
||||||
|
|
||||||
|
|
||||||
$("#playerName").html(userName);
|
$("#playerName").html(userName);
|
||||||
|
|
||||||
|
|
||||||
ws = new WebSocket($("body").data("ws-url"));
|
ws = new WebSocket($("body").data("ws-url"));
|
||||||
ws.onmessage = function (event) {
|
ws.onmessage = function (event) {
|
||||||
var message;
|
var message;
|
||||||
message = JSON.parse(event.data);
|
message = JSON.parse(event.data);
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case "refreshLobby":
|
case "refreshLobby":
|
||||||
|
if (message.lobby.status === "SelectRace()" && (!isObserver)) {
|
||||||
|
isDraftStarted = false;
|
||||||
|
renderRaces();
|
||||||
|
} else {
|
||||||
renderMaps(message.lobby.maps, message.lobby.status);
|
renderMaps(message.lobby.maps, message.lobby.status);
|
||||||
|
}
|
||||||
renderPlayersAndStats(message.lobby);
|
renderPlayersAndStats(message.lobby);
|
||||||
break;
|
break;
|
||||||
case "switchToLobby":
|
case "switchToLobby":
|
||||||
@ -132,7 +156,7 @@ window.onload = function() {
|
|||||||
break;
|
break;
|
||||||
case "sendMapBanMessage":
|
case "sendMapBanMessage":
|
||||||
console.log(message);
|
console.log(message);
|
||||||
addBanMapMessageToChat(message.message);
|
handleMapBanEvent(message.message);
|
||||||
break;
|
break;
|
||||||
case "lobbyError":
|
case "lobbyError":
|
||||||
console.log(message);
|
console.log(message);
|
||||||
@ -146,6 +170,7 @@ window.onload = function() {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onopen = function () {
|
ws.onopen = function () {
|
||||||
ws.send(JSON.stringify({
|
ws.send(JSON.stringify({
|
||||||
type: "userName",
|
type: "userName",
|
||||||
@ -156,7 +181,7 @@ window.onload = function() {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
var timerId = setInterval(() =>
|
setInterval(() =>
|
||||||
ws.send(JSON.stringify({
|
ws.send(JSON.stringify({
|
||||||
type: "getLobbies"
|
type: "getLobbies"
|
||||||
})), 2000);
|
})), 2000);
|
||||||
@ -177,7 +202,6 @@ function changeNick() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----ф-ии прихода с сервера
|
// -----ф-ии прихода с сервера
|
||||||
|
|
||||||
function switchToLobby(maps, status) {
|
function switchToLobby(maps, status) {
|
||||||
@ -199,6 +223,125 @@ function disconnectLobby(error) {
|
|||||||
alert(error);
|
alert(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------Выбор рас --------------
|
||||||
|
|
||||||
|
function getRaceImageByNumber(number) {
|
||||||
|
switch (number) {
|
||||||
|
case 1:
|
||||||
|
return "/assets/images/raceIcons/SM.gif";
|
||||||
|
case 2:
|
||||||
|
return "/assets/images/raceIcons/Chaos.gif";
|
||||||
|
case 3:
|
||||||
|
return "/assets/images/raceIcons/Eldar.gif";
|
||||||
|
case 4:
|
||||||
|
return "/assets/images/raceIcons/Orks.gif";
|
||||||
|
case 5:
|
||||||
|
return "/assets/images/raceIcons/IG.gif";
|
||||||
|
case 6:
|
||||||
|
return "/assets/images/raceIcons/Nec.gif";
|
||||||
|
case 7:
|
||||||
|
return "/assets/images/raceIcons/Tau.gif";
|
||||||
|
case 8:
|
||||||
|
return "/assets/images/raceIcons/Sob.gif";
|
||||||
|
case 9:
|
||||||
|
return "/assets/images/raceIcons/De.gif";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRaceVideoByNumber(number) {
|
||||||
|
switch (number) {
|
||||||
|
case 1:
|
||||||
|
return "/assets/video/races/SM.mp4";
|
||||||
|
case 2:
|
||||||
|
return "/assets/video/races/Chaos.mp4";
|
||||||
|
case 3:
|
||||||
|
return "/assets/video/races/Eldar.mp4";
|
||||||
|
case 4:
|
||||||
|
return "/assets/video/races/Orks.mp4";
|
||||||
|
case 5:
|
||||||
|
return "/assets/video/races/IG.mp4";
|
||||||
|
case 6:
|
||||||
|
return "/assets/video/races/Nec.mp4";
|
||||||
|
case 7:
|
||||||
|
return "/assets/video/races/Tau.mp4";
|
||||||
|
case 8:
|
||||||
|
return "/assets/video/races/Sob.mp4";
|
||||||
|
case 9:
|
||||||
|
return "/assets/video/races/SM.mp4";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderRaces() {
|
||||||
|
|
||||||
|
function getRaceSelectHtml(raceType, raceArray) {
|
||||||
|
var resHtml = "";
|
||||||
|
for(var raceNum = 1; raceNum <= raceCount; raceNum++){
|
||||||
|
resHtml += "<div class='col-xs-4'><center><h3>" + raceType + " race " + raceNum + "</h3>";
|
||||||
|
for (var i = 1; i <= 9; i++) {
|
||||||
|
var selected = "raceNotSelected";
|
||||||
|
if ($.cookie("race-" + raceType + "-" + raceNum) == i) {
|
||||||
|
selected = "raceSelected";
|
||||||
|
console.log("setted: " + i);
|
||||||
|
raceArray[raceNum] = i;
|
||||||
|
}
|
||||||
|
let raceIconClass = "raceIcon-" + raceNum + "-" + raceType;
|
||||||
|
resHtml += '<a href = "#" class="' + selected + ' ' + raceIconClass + '"' +
|
||||||
|
' onclick="selectRace(this, '+i+', '+raceNum+', \''+raceType+'\')"><img class="raceIcon" src="' + getRaceImageByNumber(i) + '"></a> ';
|
||||||
|
}
|
||||||
|
resHtml += "</center></div>";
|
||||||
|
}
|
||||||
|
return resHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resHtml = "";
|
||||||
|
resHtml += getRaceSelectHtml("main", selectedRaces);
|
||||||
|
if(existAdditionalRaces) resHtml += getRaceSelectHtml("additional", selectedAdditionalRaces);
|
||||||
|
resHtml += "<div style='clear: both;'></div></br>";
|
||||||
|
|
||||||
|
resHtml += "<center><button id = 'selectRace' class='btn btn-primary' disabled onclick='sendSelectedRacesToServer()'>OK</button></center>"
|
||||||
|
$("#mapList").html(resHtml);
|
||||||
|
checkRaceSelectFinish();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var selectedRaces = [];
|
||||||
|
var selectedAdditionalRaces = [];
|
||||||
|
|
||||||
|
function selectRace(button, race, raceNum, raceType) {
|
||||||
|
if(raceType === "main"){
|
||||||
|
selectedRaces[raceNum] = race;
|
||||||
|
}else{
|
||||||
|
selectedAdditionalRaces[raceNum] = race;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.cookie("race-" + raceType + "-" + raceNum, race, {expires: 1});
|
||||||
|
_.each($(".raceIcon-" + raceNum + "-" + raceType), function (el) {
|
||||||
|
$(el).removeClass("raceSelected");
|
||||||
|
$(el).addClass("raceNotSelected");
|
||||||
|
});
|
||||||
|
$(button).removeClass("raceNotSelected");
|
||||||
|
$(button).addClass("raceSelected");
|
||||||
|
checkRaceSelectFinish();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkRaceSelectFinish() {
|
||||||
|
if(selectedRaces.filter(x => x).length >= raceCount){
|
||||||
|
$("#selectRace").removeAttr("disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendSelectedRacesToServer() {
|
||||||
|
console.log(selectedRaces);
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
type: "selectRace",
|
||||||
|
mainRaces: selectedRaces.filter(x => x),
|
||||||
|
additionalRaces: selectedAdditionalRaces.filter(x => x)
|
||||||
|
}));
|
||||||
|
$("#mapList").html("<center>Waiting another player...</center>");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------
|
||||||
|
|
||||||
function renderMaps(maps, lobbyStatus) {
|
function renderMaps(maps, lobbyStatus) {
|
||||||
var resHtml = "";
|
var resHtml = "";
|
||||||
|
|
||||||
@ -210,19 +353,43 @@ function renderMaps(maps, lobbyStatus) {
|
|||||||
banHtml = "<div class = 'banX'>✕</div>";
|
banHtml = "<div class = 'banX'>✕</div>";
|
||||||
banClass = "bannedMap";
|
banClass = "bannedMap";
|
||||||
}
|
}
|
||||||
if(lobbyStatus === "NotStarted()"){
|
|
||||||
banClass = "bannedMap";
|
var title = ""
|
||||||
|
|
||||||
|
if (map.description != null) {
|
||||||
|
title = "title='" + map.description + "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
resHtml = resHtml + '<div class="col-xs-4 col-md-3 col-lg-2"><button class = "mapSelect" onmousedown="banMap(\'' + map.map + '\')">' +
|
resHtml = resHtml + '<div class="col-xs-4 col-md-3 col-lg-2"><button class = "mapSelect" onmousedown="banMap(\'' + map.map + '\')">' +
|
||||||
'<div class="mapImageAndText ' + banClass + '">' +
|
'<div class="mapImageAndText ' + banClass + '">' +
|
||||||
'<img class="img-rounded center-block" style="width:128px;" src="/assets/images/maps/'+encodeURI(map.map)+'.jpg">' +
|
'<img class="img-rounded center-block" ' + title + ' style="width:128px;" src="/assets/images/maps/' + encodeURI(map.map) + '.jpg">' +
|
||||||
'</div>' + convertMapName(map.map) +
|
'</div>' + convertMapName(map.map) +
|
||||||
banHtml + '</button></div>';
|
banHtml + '</button></div>';
|
||||||
})
|
})
|
||||||
$("#mapList").html(resHtml);
|
$("#mapList").html(resHtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isObserver = false;
|
||||||
|
|
||||||
|
function renderFinish(maps, firstPlayerInfo, secondPlayerInfo) {
|
||||||
|
var resHtml = "<center>";
|
||||||
|
|
||||||
|
_.each(maps, function (map) {
|
||||||
|
if (!map.isBanned) {
|
||||||
|
resHtml = resHtml + '<div class="col-xs-4 col-md-3 col-lg-2"><button class = "mapSelect" >' +
|
||||||
|
'<div class="mapImageAndText ">' +
|
||||||
|
'<img class="img-rounded center-block" style="width:128px;" src="/assets/images/maps/' + encodeURI(map.map) + '.jpg">' +
|
||||||
|
'</div>' + convertMapName(map.map) + '</button></div>';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
resHtml += "<div style='clear: both;'>";
|
||||||
|
resHtml += getRenderRaces(firstPlayerInfo, secondPlayerInfo);
|
||||||
|
resHtml += "</center>";
|
||||||
|
|
||||||
|
$("#mapList").html(resHtml);
|
||||||
|
}
|
||||||
|
|
||||||
function renderPlayersAndStats(lobby) {
|
function renderPlayersAndStats(lobby) {
|
||||||
var resHtml = "<center>";
|
var resHtml = "<center>";
|
||||||
var player1ReadyBtn = "";
|
var player1ReadyBtn = "";
|
||||||
@ -266,29 +433,34 @@ function renderPlayersAndStats(lobby) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var lobbyTypeText = "";
|
var lobbyTypeText = "";
|
||||||
|
var last1Selected = "";
|
||||||
var last3Selected = "";
|
var last3Selected = "";
|
||||||
var last4Selected = "";
|
|
||||||
var last5Selected = "";
|
var last5Selected = "";
|
||||||
var looserPickSelected = "";
|
var last7Selected = "";
|
||||||
|
|
||||||
|
var isNecronsSelected = "";
|
||||||
|
if (lobby.isNecrons) isNecronsSelected = "checked";
|
||||||
|
|
||||||
switch (lobby.selectedType) {
|
switch (lobby.selectedType) {
|
||||||
|
case "Last1()":
|
||||||
|
looserPickSelected = "selected";
|
||||||
|
lobbyTypeText = "Play on last map";
|
||||||
|
break;
|
||||||
case "Last3()":
|
case "Last3()":
|
||||||
last3Selected = "selected";
|
last3Selected = "selected";
|
||||||
lobbyTypeText = "Play on last 3 maps";
|
lobbyTypeText = "Play on last 3 maps";
|
||||||
break;
|
break;
|
||||||
case "Last4()":
|
|
||||||
last4Selected = "selected";
|
|
||||||
lobbyTypeText = "Play on last 4 maps";
|
|
||||||
break;
|
|
||||||
case "Last5()":
|
case "Last5()":
|
||||||
last5Selected = "selected";
|
last5Selected = "selected";
|
||||||
lobbyTypeText = "Play on last 5 maps";
|
lobbyTypeText = "Play on last 5 maps";
|
||||||
break;
|
break;
|
||||||
case "LooserPick()":
|
case "Last7()":
|
||||||
looserPickSelected = "selected";
|
last7Selected = "selected";
|
||||||
lobbyTypeText = "Play on last map";
|
lobbyTypeText = "Play on last 7 maps";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(lobby.status);
|
||||||
switch (lobby.status) {
|
switch (lobby.status) {
|
||||||
case "NotStarted()":
|
case "NotStarted()":
|
||||||
resHtml = "<div style='float: left; padding-top: 10px;'> <div>" + lobby.user1Info.name + ": " + player1ReadyBtn + "</div><br/>"
|
resHtml = "<div style='float: left; padding-top: 10px;'> <div>" + lobby.user1Info.name + ": " + player1ReadyBtn + "</div><br/>"
|
||||||
@ -308,26 +480,39 @@ function renderPlayersAndStats(lobby) {
|
|||||||
if (lobby.user1Info.name !== userName) {
|
if (lobby.user1Info.name !== userName) {
|
||||||
disabledText = "disabled";
|
disabledText = "disabled";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: here from config
|
||||||
resHtml += "<br/><select class=\"form-control\" id = 'deciderOption' onChange='changeLobbyType()' " + disabledText + " >" +
|
resHtml += "<br/><select class=\"form-control\" id = 'deciderOption' onChange='changeLobbyType()' " + disabledText + " >" +
|
||||||
"<option "+last3Selected+" value = 'last3'>Play on last 3 maps (BO3)</option>" +
|
"<option " + last1Selected + " value = 'last1'>Play on last map</option>" +
|
||||||
"<option "+last5Selected+" value = 'last5'>Play on last 5 maps (BO5)</option>" +
|
"<option " + last3Selected + " value = 'last3'>Play on last 3 maps</option>" +
|
||||||
"</select>"
|
"<option " + last5Selected + " value = 'last5'>Play on last 5 maps</option>" +
|
||||||
|
"<option " + last7Selected + " value = 'last7'>Play on last 7 maps</option>" +
|
||||||
|
"</select>";
|
||||||
|
|
||||||
|
if (lobby.user1Info.name !== userName && lobby.user2Info.name !== userName) {
|
||||||
|
disabledText = "disabled";
|
||||||
|
} else {
|
||||||
|
disabledText = "";
|
||||||
|
}
|
||||||
resHtml += "</div>";
|
resHtml += "</div>";
|
||||||
break;
|
break;
|
||||||
|
case "SelectRace()":
|
||||||
|
|
||||||
|
resHtml = "<center>" + lobby.user1Info.name + " vs " + lobby.user2Info.name + " - " + lobbyTypeText + "<br/> players select races</center>";
|
||||||
|
break;
|
||||||
case "Draft()":
|
case "Draft()":
|
||||||
console.log(lobby.turn);
|
if (!isDraftStarted) {
|
||||||
|
isDraftStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
var playerTurn = (lobby.playerTurn === 1) ? lobby.user1Info.name : lobby.user2Info.name
|
var playerTurn = (lobby.playerTurn === 1) ? lobby.user1Info.name : lobby.user2Info.name
|
||||||
resHtml = "<center>"+lobby.user1Info.name + " vs " + lobby.user2Info.name + " - " +lobbyTypeText+ "<br/><b>" + playerTurn +"</b> turn</center>";
|
resHtml = "<center><br/>";
|
||||||
|
resHtml += getRenderRaces(lobby.user1Info, lobby.user2Info);
|
||||||
|
resHtml += "<br/> <b>" + playerTurn + "</b> turn" + "</center>";
|
||||||
break;
|
break;
|
||||||
case "Finish()":
|
case "Finish()":
|
||||||
var lastMaps = _.filter(lobby.maps, function (map){
|
renderFinish(lobby.maps, lobby.user1Info, lobby.user2Info);
|
||||||
return map.isBanned === false;
|
break;
|
||||||
});
|
|
||||||
resHtml = "<center><b>";
|
|
||||||
_.forEach(lastMaps,function (map){
|
|
||||||
resHtml += convertMapName(map.map) + "; "
|
|
||||||
})
|
|
||||||
resHtml += "</b></center>";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resHtml = resHtml + "</center>"
|
resHtml = resHtml + "</center>"
|
||||||
@ -335,6 +520,27 @@ function renderPlayersAndStats(lobby) {
|
|||||||
$("#playersStatsList").html(resHtml);
|
$("#playersStatsList").html(resHtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRenderRaces(userInfo1, userInfo2) {
|
||||||
|
|
||||||
|
function getRacesBlock(playerRaces, name){
|
||||||
|
let resHtml = "<div style='display: inline-block; border: black 1px solid; background-color: #e3e3e3;'>" + "<h4>" + name + "</h4>";
|
||||||
|
resHtml += "main:";
|
||||||
|
playerRaces.mainRaces.forEach((raceId) =>
|
||||||
|
resHtml += "<img class=\"raceIcon\" src=" + getRaceImageByNumber(raceId) + "> ");
|
||||||
|
resHtml += "<br/> addt:";
|
||||||
|
playerRaces.additionalRaces.forEach((raceId) =>
|
||||||
|
resHtml += "<img class=\"raceIcon\" src=" + getRaceImageByNumber(raceId) + "> ");
|
||||||
|
resHtml += "</div>";
|
||||||
|
return resHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
let resHtml = "";
|
||||||
|
resHtml += getRacesBlock(userInfo1.selectedRaces, userInfo1.name);
|
||||||
|
resHtml += "<div style='width: 100px; font-size: 24px; display: inline-block;'><b>VS</b></div>";
|
||||||
|
resHtml += getRacesBlock(userInfo2.selectedRaces, userInfo2.name);
|
||||||
|
return resHtml;
|
||||||
|
}
|
||||||
|
|
||||||
function addMessageToChat(message) {
|
function addMessageToChat(message) {
|
||||||
var messageHtml = "<div class='msgln'> <b>" + message.userName + "</b>: " + message.message + "<br></div>";
|
var messageHtml = "<div class='msgln'> <b>" + message.userName + "</b>: " + message.message + "<br></div>";
|
||||||
var chatBox = $("#chatbox");
|
var chatBox = $("#chatbox");
|
||||||
@ -342,7 +548,13 @@ function addMessageToChat(message){
|
|||||||
chatBox.scrollTop(40000);
|
chatBox.scrollTop(40000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addBanMapMessageToChat(message){
|
function handleMapBanEvent(message) {
|
||||||
|
if (!isMuted) {
|
||||||
|
var audioPick = new Audio('/assets/sound/pick.mp3.mpeg');
|
||||||
|
audioPick.volume = 0.1;
|
||||||
|
audioPick.play();
|
||||||
|
}
|
||||||
|
|
||||||
var messageHtml = "<div class='msgln'><span style='color: #2C3D9B'>" + convertMapName(message.mapTechName) + "</span> banned by " + message.user + "<br></div>";
|
var messageHtml = "<div class='msgln'><span style='color: #2C3D9B'>" + convertMapName(message.mapTechName) + "</span> banned by " + message.user + "<br></div>";
|
||||||
var chatBox = $("#chatbox");
|
var chatBox = $("#chatbox");
|
||||||
chatBox.append(messageHtml);
|
chatBox.append(messageHtml);
|
||||||
@ -376,7 +588,16 @@ function changeLobbyType(){
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeIsNecronSelected() {
|
||||||
|
var isNecronSelected = $("#isNecron").is(':checked');
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
type: "changeIsNecronSelected",
|
||||||
|
isNecronSelected: isNecronSelected
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
function joinDecider(actorName) {
|
function joinDecider(actorName) {
|
||||||
|
isObserver = false;
|
||||||
ws.send(JSON.stringify({
|
ws.send(JSON.stringify({
|
||||||
type: "joinDecider",
|
type: "joinDecider",
|
||||||
lobbyActorName: actorName
|
lobbyActorName: actorName
|
||||||
@ -384,6 +605,7 @@ function joinDecider(actorName){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function observerDecider(actorName) {
|
function observerDecider(actorName) {
|
||||||
|
isObserver = true;
|
||||||
ws.send(JSON.stringify({
|
ws.send(JSON.stringify({
|
||||||
type: "observerDecider",
|
type: "observerDecider",
|
||||||
lobbyActorName: actorName
|
lobbyActorName: actorName
|
||||||
@ -409,6 +631,10 @@ function kickSecondPlayer(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function convertMapName(techMapName) {
|
function convertMapName(techMapName) {
|
||||||
var mapName = techMapName.replace("2p_", "").replaceAll("_", " ") + " (2)";
|
var mapPlayerSize = techMapName.charAt(0);
|
||||||
|
var mapName = techMapName.replace(mapPlayerSize + "p_", "").replaceAll("_", " ") +
|
||||||
|
" (" + mapPlayerSize + ")";
|
||||||
|
|
||||||
|
|
||||||
return mapName.charAt(0).toUpperCase() + mapName.slice(1);
|
return mapName.charAt(0).toUpperCase() + mapName.slice(1);
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
app/assets/sound/4playersDraft.mp3
Normal file
BIN
app/assets/sound/blip.mp3
Normal file
BIN
app/assets/sound/pick.mp3.mpeg
Normal file
BIN
app/assets/sound/started.mp3
Normal file
@ -20,6 +20,13 @@
|
|||||||
-webkit-filter: grayscale(1); /* Webkit браузеры */
|
-webkit-filter: grayscale(1); /* Webkit браузеры */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bannedRace {
|
||||||
|
height: 96px;
|
||||||
|
background-color: red;
|
||||||
|
clip-path: polygon(20% 0%, 0% 20%, 30% 50%, 0% 80%, 20% 100%, 50% 70%, 80% 100%, 100% 80%, 70% 50%, 100% 20%, 80% 0%, 50% 30%);
|
||||||
|
border: 2px solid red;
|
||||||
|
}
|
||||||
|
|
||||||
.mapSelect{
|
.mapSelect{
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
position:relative;
|
position:relative;
|
||||||
@ -29,6 +36,39 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.raceIcon{
|
||||||
|
width: 60px;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin: 3px;
|
||||||
|
border: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.raceNotSelected{
|
||||||
|
-webkit-filter: grayscale(1); /* Webkit браузеры */
|
||||||
|
}
|
||||||
|
|
||||||
|
.raceNotSelected:hover{
|
||||||
|
-webkit-filter: grayscale(0); /* Webkit браузеры */
|
||||||
|
}
|
||||||
|
|
||||||
|
.raceSelected{
|
||||||
|
-webkit-filter: brightness(1.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip span{
|
||||||
|
border-radius: 5px 5px 5px 5px;
|
||||||
|
visibility: hidden;
|
||||||
|
position: absolute;
|
||||||
|
left: 200px;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: -2px 2px 10px -1px #333;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip:hover span{
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes glowing {
|
@keyframes glowing {
|
||||||
0% {
|
0% {
|
||||||
box-shadow: 0 0 2px #074673;
|
box-shadow: 0 0 2px #074673;
|
||||||
|
|||||||
BIN
app/assets/video/races/Chaos.mp4
Normal file
BIN
app/assets/video/races/De.mp4
Normal file
BIN
app/assets/video/races/Eldar.mp4
Normal file
BIN
app/assets/video/races/IG.mp4
Normal file
BIN
app/assets/video/races/Nec.mp4
Normal file
BIN
app/assets/video/races/Orks.mp4
Normal file
BIN
app/assets/video/races/SM.mp4
Normal file
BIN
app/assets/video/races/Sob.mp4
Normal file
BIN
app/assets/video/races/Tau.mp4
Normal file
@ -1,5 +1,6 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
|
import actors.UserParentActor.GetAllUsers
|
||||||
import actors._
|
import actors._
|
||||||
import akka.NotUsed
|
import akka.NotUsed
|
||||||
import akka.actor._
|
import akka.actor._
|
||||||
@ -9,35 +10,39 @@ import akka.stream._
|
|||||||
import akka.stream.scaladsl._
|
import akka.stream.scaladsl._
|
||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
|
|
||||||
import javax.inject._
|
import javax.inject._
|
||||||
import org.reactivestreams.Publisher
|
import org.reactivestreams.Publisher
|
||||||
import play.api.libs.json._
|
import play.api.libs.json._
|
||||||
import play.api.mvc._
|
import play.api.mvc._
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
import scala.concurrent.{ExecutionContext, Future}
|
import scala.concurrent.{Await, ExecutionContext, Future}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class creates the actions and the websocket needed.
|
* This class creates the actions and the websocket needed.
|
||||||
*/
|
*/
|
||||||
@Singleton
|
@Singleton
|
||||||
class AdminController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
|
class AdminController @Inject()(cc: ControllerComponents, homeController: HomeController) extends AbstractController(cc) {
|
||||||
|
|
||||||
implicit val actorSystem: ActorSystem = ActorSystem()
|
implicit val actorSystem: ActorSystem = ActorSystem()
|
||||||
implicit val ec: ExecutionContext = defaultExecutionContext
|
implicit val ec: ExecutionContext = defaultExecutionContext
|
||||||
|
implicit val timeout = Timeout(100.millis)
|
||||||
|
|
||||||
// Use a direct reference to SLF4J
|
// Use a direct reference to SLF4J
|
||||||
private val logger = org.slf4j.LoggerFactory.getLogger("controllers.HomeController")
|
private val logger = org.slf4j.LoggerFactory.getLogger("controllers.HomeController")
|
||||||
|
|
||||||
|
val userParentActor: ActorRef = homeController.userParentActor
|
||||||
|
|
||||||
// Home page that renders template
|
// Home page that renders template
|
||||||
def viewAllLobbies() = Action { implicit request =>
|
def viewAllUsers() = Action { implicit request =>
|
||||||
logger.info(s"Received request from: ${request.remoteAddress}")
|
logger.info(s"Received request from: ${request.remoteAddress}")
|
||||||
Ok(views.html.admin())
|
|
||||||
|
val allUsers = userParentActor ? GetAllUsers
|
||||||
|
val res = Await.result(allUsers, Duration.Inf)
|
||||||
|
Ok(res.toString)
|
||||||
}
|
}
|
||||||
|
|
||||||
def banLobby(lobbyActorName: String): Unit = {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def reloadConfig()= Action { implicit request =>
|
def reloadConfig()= Action { implicit request =>
|
||||||
ConfigFactory.invalidateCaches()
|
ConfigFactory.invalidateCaches()
|
||||||
|
|||||||
@ -9,12 +9,17 @@ import akka.pattern.ask
|
|||||||
import akka.stream._
|
import akka.stream._
|
||||||
import akka.stream.scaladsl._
|
import akka.stream.scaladsl._
|
||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
|
import com.typesafe.config.ConfigFactory
|
||||||
import org.reactivestreams.Publisher
|
import org.reactivestreams.Publisher
|
||||||
import play.api.libs.json._
|
import play.api.libs.json._
|
||||||
import play.api.mvc._
|
import play.api.mvc._
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
import scala.concurrent.{ExecutionContext, Future}
|
import scala.concurrent.{ExecutionContext, Future}
|
||||||
|
import scala.util.Try
|
||||||
|
|
||||||
|
case class LastMapsSelectConfig(last1: Boolean, last3: Boolean, last5: Boolean, last7: Boolean)
|
||||||
|
case class RaceSelect(select: Boolean, showAtStart: Boolean)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class creates the actions and the websocket needed.
|
* This class creates the actions and the websocket needed.
|
||||||
@ -25,6 +30,8 @@ class HomeController @Inject()(cc: ControllerComponents) extends AbstractControl
|
|||||||
implicit val actorSystem: ActorSystem = ActorSystem()
|
implicit val actorSystem: ActorSystem = ActorSystem()
|
||||||
implicit val ec: ExecutionContext = defaultExecutionContext
|
implicit val ec: ExecutionContext = defaultExecutionContext
|
||||||
|
|
||||||
|
val config = ConfigFactory.load()
|
||||||
|
|
||||||
// Use a direct reference to SLF4J
|
// Use a direct reference to SLF4J
|
||||||
private val logger = org.slf4j.LoggerFactory.getLogger("controllers.HomeController")
|
private val logger = org.slf4j.LoggerFactory.getLogger("controllers.HomeController")
|
||||||
|
|
||||||
@ -32,9 +39,15 @@ class HomeController @Inject()(cc: ControllerComponents) extends AbstractControl
|
|||||||
val userParentActor: ActorRef = actorSystem.actorOf(Props(classOf[UserParentActor], actorSystem))
|
val userParentActor: ActorRef = actorSystem.actorOf(Props(classOf[UserParentActor], actorSystem))
|
||||||
|
|
||||||
// Home page that renders template
|
// Home page that renders template
|
||||||
def index() = Action { implicit request =>
|
def index(deciderName: String) = Action { implicit request =>
|
||||||
logger.info(s"Received request from: ${request.remoteAddress}")
|
logger.info(s"Received request from: ${request.remoteAddress}")
|
||||||
Ok(views.html.index())
|
val deciderHumanName = config.getString(s"deciders.$deciderName.name")
|
||||||
|
val deciderDescription = config.getString(s"deciders.$deciderName.rules")
|
||||||
|
val existAdditionalRaces = Try(config.getBoolean(s"deciders.$deciderName.existAdditionalRaces")).getOrElse(false)
|
||||||
|
val raceCount = Try(config.getInt(s"deciders.$deciderName.raceCount")).getOrElse(1)
|
||||||
|
val lastmapsSettings = LastMapsSelectConfig(true, true, true, true)
|
||||||
|
val raceSelect = RaceSelect(true, false)
|
||||||
|
Ok(views.html.index(deciderName, deciderHumanName, raceCount, deciderDescription, raceSelect, lastmapsSettings, existAdditionalRaces))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,7 +102,7 @@ class HomeController @Inject()(cc: ControllerComponents) extends AbstractControl
|
|||||||
* Returns true if the value of the Origin header contains an acceptable value.
|
* Returns true if the value of the Origin header contains an acceptable value.
|
||||||
*/
|
*/
|
||||||
def originMatches(origin: String, remoteAddress: String): Boolean = {
|
def originMatches(origin: String, remoteAddress: String): Boolean = {
|
||||||
origin.contains("139.59.210.74") || origin.contains("localhost") || origin.contains("localhost:9000") || origin.contains("localhost:19001")
|
origin.contains("89.108.83.108") || origin.contains("crosspick.ru") || origin.contains("localhost") || origin.contains("localhost:9000") || origin.contains("localhost:19001")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,7 +113,7 @@ class HomeController @Inject()(cc: ControllerComponents) extends AbstractControl
|
|||||||
val (webSocketOut: ActorRef, webSocketIn: Publisher[JsValue]) = createWebSocketConnections()
|
val (webSocketOut: ActorRef, webSocketIn: Publisher[JsValue]) = createWebSocketConnections()
|
||||||
|
|
||||||
// Create a user actor off the request id and attach it to the source
|
// Create a user actor off the request id and attach it to the source
|
||||||
val userActorFuture = createUserActor(request.id.toString, webSocketOut)
|
val userActorFuture = createUserActor(request.id.toString, request.remoteAddress, webSocketOut)
|
||||||
|
|
||||||
// Once we have an actor available, create a flow...
|
// Once we have an actor available, create a flow...
|
||||||
userActorFuture.map { userActor =>
|
userActorFuture.map { userActor =>
|
||||||
@ -178,11 +191,11 @@ class HomeController @Inject()(cc: ControllerComponents) extends AbstractControl
|
|||||||
* @param webSocketOut the "write" side of the websocket, that the user actor sends JsValue to.
|
* @param webSocketOut the "write" side of the websocket, that the user actor sends JsValue to.
|
||||||
* @return a user actor for this ws connection.
|
* @return a user actor for this ws connection.
|
||||||
*/
|
*/
|
||||||
private def createUserActor(name: String, webSocketOut: ActorRef): Future[ActorRef] = {
|
private def createUserActor(name: String, remoteAddress: String, webSocketOut: ActorRef): Future[ActorRef] = {
|
||||||
// Use guice assisted injection to instantiate and configure the child actor.
|
// Use guice assisted injection to instantiate and configure the child actor.
|
||||||
val userActorFuture = {
|
val userActorFuture = {
|
||||||
implicit val timeout = Timeout(100.millis)
|
implicit val timeout = Timeout(100.millis)
|
||||||
(userParentActor ? UserParentActor.Create(name, webSocketOut)).mapTo[ActorRef]
|
(userParentActor ? UserParentActor.Create(name, remoteAddress, webSocketOut)).mapTo[ActorRef]
|
||||||
}
|
}
|
||||||
userActorFuture
|
userActorFuture
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,26 @@
|
|||||||
@()(implicit r: Request[_])
|
@(deciderName: String, deciderHumanName: String, raceCount: Int, rules: String, raceSelect: RaceSelect, boSettings: LastMapsSelectConfig, existAdditionalRaces: Boolean)(implicit r: Request[_])
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<span id="deciderName" style="display: none">@deciderName</span>
|
||||||
|
<span id="raceCount" style="display: none">@raceCount</span>
|
||||||
|
<span id="existAdditionalRaces" style="display: none">@existAdditionalRaces</span>
|
||||||
|
<span id="last1Presence" style="display: none">@boSettings.last1</span>
|
||||||
|
<span id="last3Presence" style="display: none">@boSettings.last3</span>
|
||||||
|
<span id="last5Presence" style="display: none">@boSettings.last5</span>
|
||||||
|
<span id="last7Presence" style="display: none">@boSettings.last7</span>
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Soulstorm tournament decider</title>
|
<title>Soulstorm tournament decider</title>
|
||||||
<link rel='stylesheet' href='@routes.Assets.at("lib/bootstrap/css/bootstrap.min.css")'>
|
<link rel='stylesheet' href='@routes.Assets.at("lib/bootstrap/css/bootstrap.min.css")'>
|
||||||
<link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
|
<link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css?080422")">
|
||||||
<link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
|
<link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
|
||||||
<script type='text/javascript' src='@routes.Assets.at("lib/jquery/jquery.min.js")'></script>
|
<script type='text/javascript' src='@routes.Assets.at("lib/jquery/jquery.min.js")'></script>
|
||||||
<script type='text/javascript' src='@routes.Assets.at("lib/flot/jquery.flot.js")'></script>
|
<script type='text/javascript' src='@routes.Assets.at("lib/flot/jquery.flot.js")'></script>
|
||||||
<script type='text/javascript' src='@routes.Assets.at("lib/underscore/underscore.js")'></script>
|
<script type='text/javascript' src='@routes.Assets.at("lib/underscore/underscore.js")'></script>
|
||||||
<script type='text/javascript' src='@routes.Assets.at("lib/backbonejs/backbone.js")'></script>
|
<script type='text/javascript' src='@routes.Assets.at("lib/backbonejs/backbone.js")'></script>
|
||||||
<script type="text/javascript" src="@routes.Assets.at("lib/jquery-cookie/jquery.cookie.js")"></script>
|
<script type="text/javascript" src="@routes.Assets.at("lib/jquery-cookie/jquery.cookie.js")"></script>
|
||||||
|
<script type='text/javascript' src='@routes.Assets.at("javascripts/index.js?170823")'></script>
|
||||||
<script type='text/javascript' src='@routes.Assets.at("javascripts/index.js?030721")'></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body data-ws-url="@routes.HomeController.ws.webSocketURL()">
|
<body data-ws-url="@routes.HomeController.ws.webSocketURL()">
|
||||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||||
@ -37,6 +44,7 @@
|
|||||||
|
|
||||||
<div id = "decider" style="display:none">
|
<div id = "decider" style="display:none">
|
||||||
<button id = "exit" class="btn btn-primary">Exit</button>
|
<button id = "exit" class="btn btn-primary">Exit</button>
|
||||||
|
<button id = "mute" class="btn btn-primary">🔊</button>
|
||||||
<br/>
|
<br/>
|
||||||
<div id = "mapList" class="container"></div>
|
<div id = "mapList" class="container"></div>
|
||||||
<div id = "playersStatsList"></div>
|
<div id = "playersStatsList"></div>
|
||||||
@ -51,14 +59,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="clear: both"></div>
|
<div style="clear: both"></div>
|
||||||
<div><i><b>Правила турнира Big Boss of Summer 2021</b><br/>
|
<div><i><b>Правила турнира "@deciderHumanName"</b><br/>
|
||||||
<p>Выбор карт в БО3 и БО5 осуществляется без лузерпиков, с тремя и пятью десайдерами соответственно.
|
<p>@rules</p>
|
||||||
Игроки вычеркивают по очереди карты из маппула, пока их не останется 3 (для БО3) или 5 (для БО5).
|
<br>
|
||||||
На этих картах и проходят все матчи встречи. Затем игроки вычеркивают выбранные карты, пока не останется только одна, на которой и играется первый матч встречи.
|
|
||||||
Тот, кто первым начал вычеркивать из всего маппула, уступает оппоненту право вычеркивания первой карты из оставшихся карт-десайдеров.
|
|
||||||
Во втором и последующем матчах проигравший выбирает карту из числа выбранных 3 (5) десайдеров.</p>
|
|
||||||
<p>В суперфинале турнира оба игрока вычеркивают по две карты. После этого из оставшихся 9 карт можно брать любые, выбирает их проигравший в предыдущем матче.
|
|
||||||
Первый лузер-пик - за игроком из нижней сетки, который начинает с -1 очком.</p>
|
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ lazy val root = (project in file(".")).enablePlugins(PlayScala)
|
|||||||
|
|
||||||
scalaVersion := "2.12.8"
|
scalaVersion := "2.12.8"
|
||||||
|
|
||||||
|
cancelable in Global := true
|
||||||
|
|
||||||
// scalaz-bintray resolver needed for specs2 library
|
// scalaz-bintray resolver needed for specs2 library
|
||||||
resolvers += "scalaz-bintray" at "https://dl.bintray.com/scalaz/releases"
|
resolvers += "scalaz-bintray" at "https://dl.bintray.com/scalaz/releases"
|
||||||
@ -18,6 +19,7 @@ libraryDependencies += "org.webjars" % "jquery-cookie" % "1.4.1-1"
|
|||||||
libraryDependencies += "org.webjars.npm" % "underscore" % "1.11.0"
|
libraryDependencies += "org.webjars.npm" % "underscore" % "1.11.0"
|
||||||
libraryDependencies += "org.webjars" % "backbonejs" % "1.3.3"
|
libraryDependencies += "org.webjars" % "backbonejs" % "1.3.3"
|
||||||
|
|
||||||
|
|
||||||
libraryDependencies += guice
|
libraryDependencies += guice
|
||||||
libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2"
|
libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2"
|
||||||
|
|
||||||
|
|||||||
@ -2,15 +2,204 @@
|
|||||||
# https://www.playframework.com/documentation/latest/AllowedHostsFilter
|
# https://www.playframework.com/documentation/latest/AllowedHostsFilter
|
||||||
# Allow requests to localhost:9000.
|
# Allow requests to localhost:9000.
|
||||||
play.filters.hosts {
|
play.filters.hosts {
|
||||||
allowed = ["localhost:9000", "localhost", "139.59.210.74", "*"]
|
allowed = ["localhost:9000", "localhost", "89.108.83.108", "*", "crosspick.ru"]
|
||||||
}
|
}
|
||||||
play.http.secret.key="QCY?tAnfk?aZ?iwrNwnxIlR6CTf:123123Latabg@5241AB`R5W:1uDFN];Ik@n"
|
play.http.secret.key="QCY?tAnfk?aZ?iwrNwnxIlR6CTf:123123Latabg@5241AB`R5W:1uDFN];Ik@n"
|
||||||
play.server.http.port = 80
|
play.server.http.port = 1337
|
||||||
|
|
||||||
|
deciders{
|
||||||
|
classic{
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_meeting_of_minds"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_bloody_hell_[Ed]"]]
|
||||||
|
name = "Классический десайдер"
|
||||||
|
rules = """"""
|
||||||
|
}
|
||||||
|
freakcup{
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_meeting_of_minds"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_emerald_river"]]
|
||||||
|
raceCount = 1
|
||||||
|
name = "Десайдер freakcup"
|
||||||
|
rules = """"""
|
||||||
|
}
|
||||||
|
dredicmappool{
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_meeting_of_minds"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
["2p_emerald_river"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_bloody_hell_[Ed]"]]
|
||||||
|
raceCount = 2
|
||||||
|
name = "Десайдер DreDick"
|
||||||
|
rules = """"""
|
||||||
|
}
|
||||||
|
flazzomappool{
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_meeting_of_minds"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
["2p_emerald_river"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_bloody_hell_[Ed]"]]
|
||||||
|
raceCount = 2
|
||||||
|
name = "Десайдер flazzo"
|
||||||
|
rules = """"""
|
||||||
|
}
|
||||||
|
salats{
|
||||||
|
maps = [["винегрет"],
|
||||||
|
["грибная поляна"],
|
||||||
|
["крабовый"],
|
||||||
|
["мимоза"],
|
||||||
|
["оливье"],
|
||||||
|
["селедка под шубой"],
|
||||||
|
["цезарь"],
|
||||||
|
["из пекинской капусты"],
|
||||||
|
["гнездо глухаря"],
|
||||||
|
["летний"]]
|
||||||
|
|
||||||
|
name = "Выбираем салат на новый год"
|
||||||
|
rules = """"""
|
||||||
|
}
|
||||||
|
turtleshell{
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_meeting_of_minds"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_vortex_plateau"]]
|
||||||
|
name = "Turtle Shell tournament 3x3"
|
||||||
|
rules = """"""
|
||||||
|
}
|
||||||
|
turtleshell3x3{
|
||||||
|
maps = [["6p_fury_island"],
|
||||||
|
["6p_irridene"],
|
||||||
|
["6p_shakun_coast"],
|
||||||
|
["6p_testing_grounds"],
|
||||||
|
["6p_gear"],
|
||||||
|
["6p_platform"]]
|
||||||
|
raceCount = 3
|
||||||
|
name = "Turtle Shell tournament 3x3"
|
||||||
|
rules = """Turtle Shell tournament 3x3"""
|
||||||
|
}
|
||||||
|
winter_adventures{
|
||||||
|
maps = [["6p_ruined_greatway"],
|
||||||
|
["6p_fury_island"],
|
||||||
|
["6p_irridene"],
|
||||||
|
["6p_testing_grounds"],
|
||||||
|
["6p_paynes_retribution"],
|
||||||
|
["6p_shakun_coast"],
|
||||||
|
["6p_paynes_retribution"],
|
||||||
|
["6p_gear"]]
|
||||||
|
name = "Winter adventures"
|
||||||
|
raceCount = 3
|
||||||
|
rules = """Капитаны команд по очереди вычеркивают карты из маппула, пока их не останется 3-ри. На этих картах проходят все матчи встречи. Затем капитаны вычеркивают выбранные карты, пока не останется только одна, на которой и играется первый матч встречи. Выбор оставшихся карт встречи определяется правом лузерпика - проигравший определяет карту из оставшихся. """
|
||||||
|
}
|
||||||
|
noloody_mappool{
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"]]
|
||||||
|
name = "Noloody map pool"
|
||||||
|
raceCount = 2
|
||||||
|
rules = """См. в дискорде"""
|
||||||
|
}
|
||||||
|
dvijcup{
|
||||||
maps = ["2p_battle_marshes",
|
maps = ["2p_battle_marshes",
|
||||||
"2p_fallen_city_[Rem]",
|
"2p_fallen_city_[Rem]",
|
||||||
"2p_fata_morgana_[Rem]",
|
"2p_fata_morgana_[Rem]",
|
||||||
"2p_meeting_of_minds",
|
"2p_quests_triumph",
|
||||||
|
"2p_shrine_of_excellion_[Rem]",
|
||||||
|
"2p_titan_fall_[Rem]",
|
||||||
|
"2p_tranquilitys_end_[Rem]",
|
||||||
|
"2p_fraziersdemise",
|
||||||
|
"2p_bloody_hell",
|
||||||
|
"2p_blood_river_[Rem]",
|
||||||
|
"2p_deadly_fun_archeology"]
|
||||||
|
name = "Dvij cup"
|
||||||
|
rules = """Выбор карт в БО3 и БО5 осуществляется без лузерпиков, с тремя и пятью десайдерами соответственно.
|
||||||
|
Игроки вычеркивают по очереди карты из маппула, пока их не останется 3 (для БО3) или 5 (для БО5). На этих картах и проходят все матчи встречи.
|
||||||
|
Затем игроки вычеркивают выбранные карты, пока не останется только одна, на которой и играется первый матч встречи.
|
||||||
|
Тот, кто первым начал вычеркивать из всего маппула, уступает оппоненту право вычеркивания первой карты из оставшихся карт-десайдеров.
|
||||||
|
Во втором и последующем матчах проигравший выбирает карту из числа выбранных 3 (5) десайдеров."""
|
||||||
|
}
|
||||||
|
meatgrinder{
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_blood_river_[Rem]"]]
|
||||||
|
name = "Meat grinder"
|
||||||
|
raceCount = 1
|
||||||
|
rules = """Десайдеры выбираются методом вычеркивания до 3(5) карт, далее из оставшихся карт методом вычеркивания определяется первая карта. Игрок, начавший вычеркивание из основного пула уступает право начать вычеркивание из оставшихся карт."""
|
||||||
|
}
|
||||||
|
compatchcup{
|
||||||
|
maps = [["2p_fallen_city"],
|
||||||
|
["2p_deadly_fun_archeology"], ["2p_quests_triumph"], ["2p_battle_marshes"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_blood_river_[Rem]"]]
|
||||||
|
name = "Community patch cup"
|
||||||
|
raceCount = 1
|
||||||
|
rules = """см. в дискорде турнира"""}
|
||||||
|
medskillcup{
|
||||||
|
maps = ["2p_battle_marshes",
|
||||||
|
"2p_fallen_city_[Rem]",
|
||||||
|
"2p_fata_morgana_[Rem]",
|
||||||
|
"2p_bloody_hell_[Ed]",
|
||||||
"2p_outer_reaches",
|
"2p_outer_reaches",
|
||||||
"2p_quests_triumph",
|
"2p_quests_triumph",
|
||||||
"2p_shrine_of_excellion_[Rem]",
|
"2p_shrine_of_excellion_[Rem]",
|
||||||
@ -20,4 +209,564 @@ maps = ["2p_battle_marshes",
|
|||||||
"2p_emerald_river",
|
"2p_emerald_river",
|
||||||
"2p_deadly_fun_archeology",
|
"2p_deadly_fun_archeology",
|
||||||
"2p_blood_river_[Rem]"]
|
"2p_blood_river_[Rem]"]
|
||||||
|
name = "Med skill cup 4"
|
||||||
|
rules = """Вы и ваш оппонент перед началом матчей вычеркиваете из маппула карты, пока не останется 3. На них и играете. Для БО1 - та же самая система выбора карт. В суперфинале игрок из верхней сетки начинает с +1 очком, а игрок из нижней сетки - с лузерпиком. Далее оба игрока вычеркивают по 3 карты, и могут лузерпикать из оставшихся 6 в последующих матчах."""
|
||||||
|
}
|
||||||
|
burgercup{
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"]]
|
||||||
|
name = "Burger cup"
|
||||||
|
raceCount = 2
|
||||||
|
rules = """Выбор карт в БО3 и БО5 осуществляется без лузерпиков, с тремя и пятью десайдерами соответственно. Игроки вычеркивают по очереди карты из маппула, пока их не останется 3 (для БО3) или 5 (для БО5). На этих картах и проходят все матчи встречи. Затем игроки вычеркивают выбранные карты, пока не останется только одна, на которой и играется первый матч встречи. Тот, кто первым начал вычеркивать из всего маппула, уступает оппоненту право вычеркивания первой карты из оставшихся карт-десайдеров. Во втором и последующем матчах проигравший выбирает карту из числа выбранных 3 (5) десайдеров."""
|
||||||
|
}
|
||||||
|
trainercup{
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_deadly_fun_archeology"]]
|
||||||
|
name = "Trainer cup"
|
||||||
|
raceCount = 2
|
||||||
|
rules = """Выбор карт в БО3 и БО5 осуществляется без лузерпиков, с тремя и пятью десайдерами соответственно. Игроки вычеркивают по очереди карты из маппула, пока их не останется 3 (для БО3) или 5 (для БО5). На этих картах и проходят все матчи встречи. Затем игроки вычеркивают выбранные карты, пока не останется только одна, на которой и играется первый матч встречи. Тот, кто первым начал вычеркивать из всего маппула, уступает оппоненту право вычеркивания первой карты из оставшихся карт-десайдеров. Во втором и последующем матчах проигравший выбирает карту из числа выбранных 3 (5) десайдеров."""
|
||||||
|
}
|
||||||
|
customcup{
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"]]
|
||||||
|
name = "Custom Cup"
|
||||||
|
raceCount = 2
|
||||||
|
rules = """Выбор карт в БО3 и БО5 осуществляется без лузерпиков, с тремя и пятью десайдерами соответственно. Игроки вычеркивают по очереди карты из маппула, пока их не останется 3 (для БО3) или 5 (для БО5). На этих картах и проходят все матчи встречи. Затем игроки вычеркивают выбранные карты, пока не останется только одна, на которой и играется первый матч встречи. Тот, кто первым начал вычеркивать из всего маппула, уступает оппоненту право вычеркивания первой карты из оставшихся карт-десайдеров. Во втором и последующем матчах проигравший выбирает карту из числа выбранных 3 (5) десайдеров."""
|
||||||
|
}
|
||||||
|
everyonecup{
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_moonbase"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_meeting_of_minds"],
|
||||||
|
["2p_emperors_valley"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_sugaroasis"]]
|
||||||
|
name = "Everyone cup"
|
||||||
|
raceCount = 1
|
||||||
|
rules = """Все матчи БО3. Игроки вычеркивают по очереди карты из маппула, пока их не останется 3. На этих картах и проходят все матчи встречи."""
|
||||||
|
}
|
||||||
|
bigbosswinter{
|
||||||
|
maps = ["2p_battle_marshes",
|
||||||
|
"2p_fallen_city_[Rem]",
|
||||||
|
"2p_fata_morgana_[Rem]",
|
||||||
|
"2p_meeting_of_minds",
|
||||||
|
"2p_outer_reaches",
|
||||||
|
"2p_quests_triumph",
|
||||||
|
"2p_shrine_of_excellion_[Rem]",
|
||||||
|
"2p_titan_fall_[Rem]",
|
||||||
|
"2p_tranquilitys_end_[Rem]",
|
||||||
|
"2p_bloody_hell_[Ed]",
|
||||||
|
"2p_emerald_river",
|
||||||
|
"2p_deadly_fun_archeology",
|
||||||
|
"2p_winter_confrontation"]
|
||||||
|
name = "Big boss of winter"
|
||||||
|
rules = """Выбор карт в БО3 и БО5 осуществляется без лузерпиков, с тремя и пятью десайдерами соответственно. Игроки вычеркивают по очереди карты из маппула, пока их не останется 3 (для БО3) или 5 (для БО5). На этих картах и проходят все матчи встречи. Затем игроки вычеркивают выбранные карты, пока не останется только одна, на которой и играется первый матч встречи. Тот, кто первым начал вычеркивать из всего маппула, уступает оппоненту право вычеркивания первой карты из оставшихся карт-десайдеров. Во втором и последующем матчах проигравший выбирает карту из числа выбранных 3 (5) десайдеров.В суперфинале турнира оба игрока вычеркивают по две карты. После этого из оставшихся 9 карт можно брать любые, выбирает их проигравший в предыдущем матче. Первый лузер-пик - за игроком из нижней сетки, который начинает с -1 очком. """
|
||||||
|
}
|
||||||
|
frenchtournament{
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_meeting_of_minds"],
|
||||||
|
["2p_emerald_river"],
|
||||||
|
["2p_vortex_plateau"],
|
||||||
|
["2p_deadly_fun_archeology"]]
|
||||||
|
name = "French tournament"
|
||||||
|
raceCount = 1
|
||||||
|
rules = """ """
|
||||||
|
}
|
||||||
|
arena-bad-2{
|
||||||
|
maps = [["2p_outer_reaches"],
|
||||||
|
["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_meeting_of_minds"]]
|
||||||
|
name = "Arena bad 2"
|
||||||
|
raceCount = 1
|
||||||
|
existAdditionalRaces = true
|
||||||
|
rules = """1 раса, но можно взять вторую при мирроре"""
|
||||||
|
}
|
||||||
|
mallusc-cup{
|
||||||
|
maps = [["2p_outer_reaches"],
|
||||||
|
["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_meeting_of_minds"],
|
||||||
|
["2p_emerald_river"],
|
||||||
|
["2p_fraziersdemise"]]
|
||||||
|
name = "Маллюск кап"
|
||||||
|
raceCount = 1
|
||||||
|
existAdditionalRaces = true
|
||||||
|
rules = """"""
|
||||||
|
}
|
||||||
|
showmatch{
|
||||||
|
maps = [["2p_outer_reaches"],
|
||||||
|
["2p_battle_marshes"],
|
||||||
|
["2p_vortex_plateau"],
|
||||||
|
["2p_velvet_duress"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_meeting_of_minds"],
|
||||||
|
["2p_emerald_river"],
|
||||||
|
["2p_fraziersdemise"]]
|
||||||
|
name = "Маллюск кап"
|
||||||
|
raceCount = 1
|
||||||
|
existAdditionalRaces = true
|
||||||
|
rules = """"""
|
||||||
|
}
|
||||||
|
mallusc-cup{
|
||||||
|
maps = [["2p_outer_reaches"],
|
||||||
|
["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_meeting_of_minds"],
|
||||||
|
["2p_emerald_river"],
|
||||||
|
["2p_fraziersdemise"]]
|
||||||
|
name = "Маллюск кап"
|
||||||
|
raceCount = 1
|
||||||
|
existAdditionalRaces = true
|
||||||
|
rules = """"""
|
||||||
|
}
|
||||||
|
horusheresycup2{
|
||||||
|
maps = ["2p_battle_marshes",
|
||||||
|
"2p_fallen_city_[Rem]",
|
||||||
|
"2p_fata_morgana_[Rem]",
|
||||||
|
"2p_quests_triumph",
|
||||||
|
"2p_shrine_of_excellion_[Rem]",
|
||||||
|
"2p_titan_fall_[Rem]",
|
||||||
|
"2p_tranquilitys_end_[Rem]",
|
||||||
|
"2p_outer_reaches",
|
||||||
|
"2p_blood_river_[Rem]",
|
||||||
|
"2p_sugaroasis",
|
||||||
|
"2p_meeting_of_minds"]
|
||||||
|
name = "Horus heresy cup 2"
|
||||||
|
rules = """ Первая карта десайдер выбирается методом вычеркивания, остальные лузер пик. По обоюдному согласию игроков разрешен повтор карт. Сетка турнира Double Elimination.
|
||||||
|
Сетка виннеров:
|
||||||
|
Каждая игра до 2х победы (БО3),
|
||||||
|
В суперфинале игра до 3-х побед (БО5).
|
||||||
|
Сетка лузеров:
|
||||||
|
Каждая игра до 1й победы (БО1),
|
||||||
|
Финал сетки лузеров (БО3).
|
||||||
|
Игрок, прошедший в суперфинал из верхней сетки, имеет +1 очко. Игрок из нижней сетки начинает с лузерпиком. """
|
||||||
|
}
|
||||||
|
shouldercup{
|
||||||
|
description = true
|
||||||
|
existAdditionalRaces = true
|
||||||
|
raceCount = 3
|
||||||
|
maps = [["6p_paynes_retribution", "Количество точек: 28/2/2\nСпорных точек: 10/0/2\nТермогенераторы: 2"],
|
||||||
|
["6p_fury_island", "Количество точек: 26/6/1\nСпорных точек: 6 + 1 крит\nТермогенераторы: Отсутствуют"],
|
||||||
|
["6p_irridene", "Количество точек: 21/6/3\nСпорных точек: 6/0/3\nТермогенераторы: 6"],
|
||||||
|
["6p_shakun_coast", "Количество точек: 24/4/1\nСпорных точек: 6/2/1\nТермогенераторы: 2"],
|
||||||
|
"2p_tranquilitys_end_[Rem]",
|
||||||
|
"2p_outer_reaches",
|
||||||
|
"2p_blood_river_[Rem]",
|
||||||
|
"2p_sugaroasis",
|
||||||
|
"2p_meeting_of_minds"]
|
||||||
|
name = "Horus heresy cup 2"
|
||||||
|
rules = """ Первая карта десайдер выбирается методом вычеркивания, остальные лузер пик. По обоюдному согласию игроков разрешен повтор карт. Сетка турнира Double Elimination.
|
||||||
|
Сетка виннеров:
|
||||||
|
Каждая игра до 2х победы (БО3),
|
||||||
|
В суперфинале игра до 3-х побед (БО5).
|
||||||
|
Сетка лузеров:
|
||||||
|
Каждая игра до 1й победы (БО1),
|
||||||
|
Финал сетки лузеров (БО3).
|
||||||
|
Игрок, прошедший в суперфинал из верхней сетки, имеет +1 очко. Игрок из нижней сетки начинает с лузерпиком. """
|
||||||
|
}
|
||||||
|
shouldercup{
|
||||||
|
description = true
|
||||||
|
existAdditionalRaces = true
|
||||||
|
raceCount = 3
|
||||||
|
maps = [["6p_paynes_retribution", "Количество точек: 28/2/2\nСпорных точек: 10/0/2\nТермогенераторы: 2"],
|
||||||
|
["6p_fury_island", "Количество точек: 26/6/1\nСпорных точек: 6 + 1 крит\nТермогенераторы: Отсутствуют"],
|
||||||
|
["6p_irridene", "Количество точек: 21/6/3\nСпорных точек: 6/0/3\nТермогенераторы: 6"],
|
||||||
|
["6p_shakun_coast", "Количество точек: 24/4/1\nСпорных точек: 6/2/1\nТермогенераторы: 2"],
|
||||||
|
"2p_tranquilitys_end_[Rem]",
|
||||||
|
"2p_outer_reaches",
|
||||||
|
"2p_blood_river_[Rem]",
|
||||||
|
"2p_sugaroasis",
|
||||||
|
"2p_meeting_of_minds"]
|
||||||
|
name = "Horus heresy cup 2"
|
||||||
|
rules = """ Первая карта десайдер выбирается методом вычеркивания, остальные лузер пик. По обоюдному согласию игроков разрешен повтор карт. Сетка турнира Double Elimination.
|
||||||
|
Сетка виннеров:
|
||||||
|
Каждая игра до 2х победы (БО3),
|
||||||
|
В суперфинале игра до 3-х побед (БО5).
|
||||||
|
Сетка лузеров:
|
||||||
|
Каждая игра до 1й победы (БО1),
|
||||||
|
Финал сетки лузеров (БО3).
|
||||||
|
Игрок, прошедший в суперфинал из верхней сетки, имеет +1 очко. Игрок из нижней сетки начинает с лузерпиком. """
|
||||||
|
}
|
||||||
|
shouldercup{
|
||||||
|
description = true
|
||||||
|
existAdditionalRaces = true
|
||||||
|
raceCount = 3
|
||||||
|
maps = [["6p_paynes_retribution", "Количество точек: 28/2/2\nСпорных точек: 10/0/2\nТермогенераторы: 2"],
|
||||||
|
["6p_fury_island", "Количество точек: 26/6/1\nСпорных точек: 6 + 1 крит\nТермогенераторы: Отсутствуют"],
|
||||||
|
["6p_irridene", "Количество точек: 21/6/3\nСпорных точек: 6/0/3\nТермогенераторы: 6"],
|
||||||
|
["6p_shakun_coast", "Количество точек: 24/4/1\nСпорных точек: 6/2/1\nТермогенераторы: 2"],
|
||||||
|
["6p_platform", "Количество точек: 26/2/3\nТермогенераторы: 2"],
|
||||||
|
["6p_temple_cyrene", "Количество точек: 25/4/5\nСпорных точек: 8/0/3\nТермогенераторы: 2"],
|
||||||
|
["6p_testing_grounds", "Количество точек: 32/6/5\nСпорных точек: 10/2/5\nТермогенераторы: 6"],
|
||||||
|
["6p_ruined_greatway", "Количество точек: 22/2/1\nСпорных точек: 2/2/1\nТермогенераторы: 2"],
|
||||||
|
["6p_gear", "Количество точек: 24/2/3\nСпорных точек: 2 крита, но ввиду контактности карты сражение может идти на большинстве внешних точек\nТермогенераторы: 2"]]
|
||||||
|
name = "Shoulder to shoulder cup"
|
||||||
|
rules = """Классическая Double elimination с сеткой лузеров. В сетке виннеров - БО3, в сетке лузеров - БО1, в суперфинале - БО5. Игрок, прошедший в суперфинал из верхней сетки, имеет +1 очко. Игрок из нижней сетки начинает с лузерпиком. """
|
||||||
|
}
|
||||||
|
shouldercup4x4{
|
||||||
|
description = true
|
||||||
|
raceCount = 4
|
||||||
|
maps = [["8p_burial_grounds", "Количество стратегических/реликтовых/критических точек: 32/2/4\nСпорных точек: 4/2/2\nТермогенераторы: 3"],
|
||||||
|
["8p_daturias_pits", "Количество стратегических/реликтовых/критических точек: 32/4/5\nСпорных точек: 2/2/1\nТермогенераторы: 0"],
|
||||||
|
["8p_forbidden_jungle", "Количество стратегических/реликтовых/критических точек: 36/5/0\nСпорных точек: 12/5/0\nТермогенераторы: 4"],
|
||||||
|
["8p_demes_northlands", "Количество стратегических/реликтовых/критических точек: 32/4/3\nСпорных точек: 3/2/2\nТермогенераторы: 2"],
|
||||||
|
["8p_glacier", "Количество стратегических/реликтовых/критических точек: 24/4/5\nСпорных точек: 0/0/4\nТермогенераторы: 4"],
|
||||||
|
["8p_jalaganda_lowlands", "Количество стратегических/реликтовых/критических точек: 26/5/3\nСпорных точек: 2/1/3\nТермогенераторы: 0"],
|
||||||
|
["8p_monse", "Количество стратегических/реликтовых/критических точек: 26/4/4\nСпорных точек: 2/2/4\nТермогенераторы: 1"],
|
||||||
|
["8p_thurabis_plateau", "Количество стратегических/реликтовых/критических точек: 32/2/0\nСпорных точек: 12/2/0\nТермогенераторы: 0"],
|
||||||
|
["8p_verdant_isles_ed", "Количество стратегических/реликтовых/критических точек: 32/4/3\nСпорных точек: 0/4/3\nТермогенераторы: 0"]]
|
||||||
|
name = "Shoulder to shoulder cup"
|
||||||
|
rules = """Черкается по правилу лузерпиков: сначала оставляется одна карта, далее команда выбирает, на какой карте будет играть. """
|
||||||
|
}
|
||||||
|
springcup{
|
||||||
|
description = true
|
||||||
|
maps = [["4p_biffys_peril"],
|
||||||
|
["4p_cold_war"],
|
||||||
|
["4p_colosseum_of_deadman"],
|
||||||
|
["4p_gorhael_crater"],
|
||||||
|
["4p_imperial_area"],
|
||||||
|
["4p_saints_square"],
|
||||||
|
["4p_tartarus_center"],
|
||||||
|
["4p_testcake"],
|
||||||
|
["4p_skerries"],
|
||||||
|
["4p_tiboraxx"],
|
||||||
|
["4p_torrents"]]
|
||||||
|
name = "Spring cup 2x2"
|
||||||
|
rules = """Десайдеры выбирается методом вычеркивания до 3 карт, далее из оставшихся карт методом вычеркивания определяется первая карта. Игрок, начавший вычеркивание из основного пула уступает право начать вычеркивание из оставшихся карт. Исключение суперфинал: Команда прошедшая в суперфинал с верхней сетки имеет преимущество в выборе очередности карт из оставшихся 3 после вычеркивания."""
|
||||||
|
}
|
||||||
|
shouldercup2x2{
|
||||||
|
description = true
|
||||||
|
raceCount = 2
|
||||||
|
existAdditionalRaces = true
|
||||||
|
maps = [["4p_biffys_peril"],
|
||||||
|
["4p_cold_war"],
|
||||||
|
["4p_colosseum_of_deadman"],
|
||||||
|
["4p_chaos_platenau"],
|
||||||
|
["4p_imperial_area"],
|
||||||
|
["4p_saints_square"],
|
||||||
|
["4p_tartarus_center"],
|
||||||
|
["4p_skerries"],
|
||||||
|
["4p_gurmuns_pass"]]
|
||||||
|
name = "Shoulder cup 2x2"
|
||||||
|
rules = """Расы в командах (как основные, так и дополнительные) должны соблюдать правило - в команде должен быть только один представитель следующих рас: тау, эльдар. В случае поражения на одной из карт, противники могут лузерпикать свои расы на дополнительные (причем допрасы берут все игроки команды и могут мешать), но при этом заранее уведомляют будут ли играть данной связкой рас на следующей карте (в случае если лузерпик произошел на второй карте в рамках Best of 3). Расы свободно выбираются каждое БО 1/3/5 на протяжении турнира. Позиции можно выбирать по договоренности с командами."""
|
||||||
|
}
|
||||||
|
sweatybarrakcup{
|
||||||
|
description = true
|
||||||
|
maps =[["2p_chaos_gate"],
|
||||||
|
["2p_colosseum_suicide"],
|
||||||
|
["2p_emerald_river"],
|
||||||
|
["2p_faceoff"],
|
||||||
|
["2p_moonbase_[Ed]"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
["2p_fear"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_terror_psyclaw"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_velvet_duress"],
|
||||||
|
["2p_winter_confortation"],
|
||||||
|
["2p_deadly_fun_archeology"]]
|
||||||
|
name = "Sweaty barrack cup"
|
||||||
|
rules = """Перед началом матча, игроки поочередно вычеркивают по одной карте, пока не выберут десайдер. Если иного не сказано в секции "Расы" (см. ограничения для рас). Во второй и всех последующих играх - побежденный выбирает карту.
|
||||||
|
Чтобы не было повторений карт, игроки могу выбрать всего 1 раз карту из списка. """
|
||||||
|
}
|
||||||
|
tpmodcup{
|
||||||
|
description = true
|
||||||
|
raceCount = 1
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_fear"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_faceoff"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_terror_psyclaw"],
|
||||||
|
["2p_meeting_of_minds_pro", "Модифицированная версия Meeting of minds v 1.0: 6 точек на игрока, одна из которой находится за реликтом."],
|
||||||
|
["2p_edemus_gamble"],
|
||||||
|
["[tp_mod]jungle_morning"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["[tp_mod]light_brigade"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
["2p_vortex_plateau"]]
|
||||||
|
name = "Турнир по ТП моду"
|
||||||
|
rules = """Первая карта десайдер выбирается методом вычеркивания, остальные лузер пик. """
|
||||||
|
}
|
||||||
|
bestfriendscup{
|
||||||
|
maps = ["4p_gorhael_crater",
|
||||||
|
"4p_gurmuns_pass",
|
||||||
|
"4p_saints_square",
|
||||||
|
"4p_skerries",
|
||||||
|
"4p_panrea_lowlands",
|
||||||
|
"4p_doom_spiral",
|
||||||
|
"4p_tiboraxx"]
|
||||||
|
name = "Best friends cup cup"
|
||||||
|
rules = """ Обе команды вычеркивают по очереди неудобные для себя карты. Каждая команда вычеркивает в общей сложности 3. На оставшейся, седьмой карте, проходит Ваш первый матч - она называется десайдером. Во всех последующих играх карту выбирает команда, проигравшая в последнем матче. Это называется лузерпиком - выбором проигравших. В суперфинале турнира сражается команда из сетки виннеров против финалистов из сетки лузеров, в формате БО5 (до трёх побед). """
|
||||||
|
}
|
||||||
|
noweaknesscup{
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"]]
|
||||||
|
name = "No Weakness cup"
|
||||||
|
rules = """Выбор карт в БО3 и БО5 осуществляется без лузерпиков, с тремя и пятью десайдерами соответственно. Игроки вычеркивают по очереди карты из маппула, пока их не останется 3 (для БО3) или 5 (для БО5). На этих картах и проходят все матчи встречи. Затем игроки вычеркивают выбранные карты, пока не останется только одна, на которой и играется первый матч встречи. Тот, кто первым начал вычеркивать из всего маппула, уступает оппоненту право вычеркивания первой карты из оставшихся карт-десайдеров. Во втором и последующем матчах проигравший выбирает карту из числа выбранных 3 (5) десайдеров. """
|
||||||
|
}
|
||||||
|
freneticmappool{
|
||||||
|
raceCount = 1
|
||||||
|
description = true
|
||||||
|
maps =[["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_emerald_river"],
|
||||||
|
["2p_chaos_gate"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["2p_meeting_of_minds"]],
|
||||||
|
name = "Frenetic map pool"
|
||||||
|
rules = """ """
|
||||||
|
}
|
||||||
|
freneticmappool2{
|
||||||
|
raceCount = 2
|
||||||
|
description = true
|
||||||
|
maps =[["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_emerald_river"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_meeting_of_minds"]]
|
||||||
|
name = "Frenetic map pool"
|
||||||
|
rules = """ """
|
||||||
|
}
|
||||||
|
freneticmappool2x2{
|
||||||
|
raceCount = 2
|
||||||
|
description = true
|
||||||
|
maps =[["4p_biffys_peril"],
|
||||||
|
["4p_chaos_platenau"],
|
||||||
|
["4p_cold_war"],
|
||||||
|
["4p_gorhael_crater"],
|
||||||
|
["4p_gurmuns_pass"],
|
||||||
|
["4p_imperial_area"],
|
||||||
|
["4p_marconia"],
|
||||||
|
["4p_panrea_lowlands"],
|
||||||
|
["4p_saints_square"],
|
||||||
|
["4p_snowblind"],
|
||||||
|
["4p_tartarus_center"],
|
||||||
|
["4p_skerries"],
|
||||||
|
["4p_doom_spiral"]]
|
||||||
|
name = "Frenetic map pool"
|
||||||
|
rules = """ """
|
||||||
|
}
|
||||||
|
deadgamecup{
|
||||||
|
raceCount = 2
|
||||||
|
description = true
|
||||||
|
maps =[["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city", "Обратите внимание, не ремастер"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_outer_reaches"]]
|
||||||
|
name = "Dead game cup"
|
||||||
|
rules = """ """
|
||||||
|
}
|
||||||
|
casinocup {
|
||||||
|
raceCount = 2
|
||||||
|
maps = [["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_fraziersdemise"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
["2p_meeting_of_minds"]]
|
||||||
|
name = "Casino cup"
|
||||||
|
rules = """Выбор карт без лузерпиков, с тремя и пятью десайдерами соответственно. Игроки вычеркивают по очереди карты из маппула, пока их не останется 3 (для БО3) или 5 (для БО5). На этих картах и проходят все матчи встречи. Затем игроки вычеркивают выбранные карты, пока не останется только одна, на которой и играется первый матч встречи. Тот, кто первым начал вычеркивать из всего маппула, уступает оппоненту право вычеркивания первой карты из оставшихся карт-десайдеров. Во втором и последующем матчах проигравший выбирает карту из числа выбранных 3 (5) десайдеров. """
|
||||||
|
}
|
||||||
|
badcup {
|
||||||
|
raceCount = 2
|
||||||
|
maps = [["2p_outer_reaches"],
|
||||||
|
["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_blood_river_[Rem]"]
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_meeting_of_minds"],
|
||||||
|
["2p_emerald_river"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
]
|
||||||
|
name = "BAD cup"
|
||||||
|
rules = """Double elimination. БО3 (БО5 суперфинал). БО1 лузерсетка (БО3 финал лузер сетки). 2 Расы на турнир, без банов. Вторая раса берётся в случае лузерпика(и играется до окончания бо) или по договоренности обеих сторон в случае миррора."""
|
||||||
|
}
|
||||||
|
uacup{
|
||||||
|
raceCount = 0
|
||||||
|
maps = [["2p_belltower"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_emerald_river"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
]
|
||||||
|
name = "UA cup"
|
||||||
|
rules = """"""
|
||||||
|
}
|
||||||
|
true_arena_bad2{
|
||||||
|
raceCount = 2
|
||||||
|
maps = [["2p_outer_reaches"],
|
||||||
|
["2p_battle_marshes"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_blood_river_[Rem]"]
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_meeting_of_minds"],
|
||||||
|
["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
]
|
||||||
|
name = "BAD cup"
|
||||||
|
rules = """"""
|
||||||
|
}
|
||||||
|
ppcz {
|
||||||
|
raceCount = 2
|
||||||
|
maps = [["2p_fata_morgana_[Rem]"],
|
||||||
|
["2p_titan_fall_[Rem]"],
|
||||||
|
["2p_tranquilitys_end_[Rem]"],
|
||||||
|
["2p_shrine_of_excellion_[Rem]"],
|
||||||
|
["2p_quests_triumph"],
|
||||||
|
["2p_fallen_city_[Rem]"],
|
||||||
|
["2p_outer_reaches"],
|
||||||
|
["2p_battle_marshes"],
|
||||||
|
["2p_sugaroasis"],
|
||||||
|
["2p_bloody_hell_[Ed]"],
|
||||||
|
["2p_deadly_fun_archeology"],
|
||||||
|
["2p_blood_river_[Rem]"],
|
||||||
|
["2p_meeting_of_minds"]]
|
||||||
|
name = "PPCZ"
|
||||||
|
rules = """
|
||||||
|
Игрок выбирает основную и дополнительную расу (по желанию). Первая игра всегда играется основной расой. Начиная со второй игры проигравший может взять дополнительную расу, при этом победивший не может поменять расу.
|
||||||
|
|
||||||
|
Эльдар не имеет права лузерпикать против SM, IG, CSM (вместо этого карту выбирает оппонент)
|
||||||
|
|
||||||
|
Некрон не имеет права лузерпикать против Tau (тоже, что и в примере выше)
|
||||||
|
Против некрона нельзя выбирать SOE лузерпиком (Tau все еще может выбирать любую карту против некрона"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,41 +1,48 @@
|
|||||||
|
<!--
|
||||||
|
Copyright (C) Lightbend Inc. <https://www.lightbend.com>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- The default logback configuration that Play uses if no other configuration is provided -->
|
||||||
<configuration>
|
<configuration>
|
||||||
|
|
||||||
<conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel" />
|
<conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel" />
|
||||||
|
|
||||||
<property name="LOG_FILE" value="logs\decider-log" />
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
|
||||||
<!-- daily rollover -->
|
|
||||||
<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.gz</fileNamePattern>
|
|
||||||
|
|
||||||
<!-- keep 30 days' worth of history capped at 3GB total size -->
|
|
||||||
<maxHistory>30</maxHistory>
|
|
||||||
<totalSizeCap>3GB</totalSizeCap>
|
|
||||||
</rollingPolicy>
|
|
||||||
<encoder>
|
<encoder>
|
||||||
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
|
<pattern>%coloredLevel %logger{15} - %message%n%xException{10}</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
|
||||||
<encoder>
|
<!-- increases the default queue size -->
|
||||||
<pattern>%coloredLevel %logger{15} - [%marker] %message%n%xException{10}</pattern>
|
<queueSize>512</queueSize>
|
||||||
</encoder>
|
<!-- don't discard messages -->
|
||||||
|
<discardingThreshold>0</discardingThreshold>
|
||||||
|
<!-- block when queue is full -->
|
||||||
|
<neverBlock>false</neverBlock>
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<logger name="play" level="INFO" />
|
<logger name="play" level="INFO" />
|
||||||
|
|
||||||
<!-- actors logging -->
|
<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF" />
|
||||||
<logger name="akka" level="DEBUG"/>
|
|
||||||
|
|
||||||
<logger name="actors" level="DEBUG"/>
|
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||||
|
<file>${application.home:-.}/logs/application.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
<!-- controllers -->
|
<appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
|
||||||
<logger name="controllers" level="DEBUG"/>
|
<appender-ref ref="FILE" />
|
||||||
|
</appender>
|
||||||
|
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="ASYNCFILE" />
|
||||||
<appender-ref ref="FILE"/>
|
<appender-ref ref="ASYNCSTDOUT" />
|
||||||
</root>
|
</root>
|
||||||
|
|
||||||
|
<shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/>
|
||||||
|
|
||||||
</configuration>
|
</configuration>
|
||||||
@ -2,15 +2,11 @@
|
|||||||
# This file defines all application routes (Higher priority routes first)
|
# This file defines all application routes (Higher priority routes first)
|
||||||
# ~~~~
|
# ~~~~
|
||||||
|
|
||||||
GET /meatgrinder controllers.HomeController.index
|
GET /decider/:name controllers.HomeController.index(name)
|
||||||
GET /bigbossofsummer controllers.HomeController.index
|
|
||||||
GET /dvijcup controllers.HomeController.index
|
|
||||||
|
|
||||||
GET /ws controllers.HomeController.ws
|
GET /ws controllers.HomeController.ws
|
||||||
|
|
||||||
GET /reloadconfig controllers.AdminController.reloadConfig
|
GET /admin/users controllers.AdminController.viewAllUsers()
|
||||||
|
|
||||||
GET /lobbyadmin controllers.AdminController.viewAllLobbies
|
|
||||||
|
|
||||||
# Map static resources from the /public folder to the /assets URL path
|
# Map static resources from the /public folder to the /assets URL path
|
||||||
GET /assets/*file controllers.Assets.at(path="/public", file)
|
GET /assets/*file controllers.Assets.at(path="/public", file)
|
||||||
|
|||||||