finished game webpage
This commit is contained in:
parent
152a71ff05
commit
f77b019b3d
125
web/cards.html
Normal file
125
web/cards.html
Normal file
@ -0,0 +1,125 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>災厄之悲歌</title>
|
||||
<!-- Tocas UI:CSS 與元件 -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocas-ui/2.3.3/tocas.css">
|
||||
<!-- Tocas JS:模塊與 JavaScript 函式 -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocas-ui/2.3.3/tocas.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
||||
<link rel="stylesheet" href="./gameUI.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="ts grid" id="grid">
|
||||
<!-- Main Container -->
|
||||
<div class="stretched column">
|
||||
<!-- Enemy information -->
|
||||
<div class="ts fluid container" style="height: 40%;" id="enemy">
|
||||
<div class="ts profile segments" style="width: 30%;">
|
||||
<div class="ts top attached name segment">
|
||||
<div class="ts center aligned header">== 等待中 ==</div>
|
||||
</div>
|
||||
<div class="ts attached life progress">
|
||||
<div class="bar" style="width:100%;" data-life="20"><span class="text">--</span></div>
|
||||
</div>
|
||||
<div class="ts status segment">
|
||||
清新
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Player Avatar -->
|
||||
<i class="massive user icon" style="opacity: 0;"></i>
|
||||
|
||||
<div class="ts info segments">
|
||||
<div class="ts segment">
|
||||
<i class="credit card icon"></i>手牌 <span id="eneHand"> -- </span>
|
||||
</div>
|
||||
<div class="ts segment">
|
||||
<i class="inbox icon"></i>牌組 <span id="eneDeck"> -- </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Game Status -->
|
||||
<div class="ts fluid container" id="game" style="height: 20%;">
|
||||
<div class="ts statistic">
|
||||
<div class="label">房號</div>
|
||||
<div class="value">00000</div>
|
||||
</div>
|
||||
<div class="ts big header" id="turn">Turn 0</div>
|
||||
<div class="ts inverted button" id="status">等待中</div>
|
||||
<div class="ts separated buttons" id="actions">
|
||||
<a class="ts disabled primary button" id="skip">跳過回合</a>
|
||||
<a class="ts negative button" id="giveup">放棄人生</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Current Player information -->
|
||||
<div class="ts fluid container" style="height: 40%;" id="myself">
|
||||
<div class="ts profile segments" style="width: 30%;">
|
||||
<div class="ts name top attached segment">
|
||||
<div class="ts center aligned header">===</div>
|
||||
</div>
|
||||
<div class="ts attached life progress">
|
||||
<div class="bar" style="width:100%" data-life="20"><span class="text">--</span></div>
|
||||
</div>
|
||||
<div class="ts status segment">
|
||||
清新
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Player Avatar -->
|
||||
<i class="massive user icon"></i>
|
||||
|
||||
<div class="ts info segments">
|
||||
<div class="ts segment">
|
||||
<i class="credit card icon"></i>手牌 <span id="selfHand">--</span>
|
||||
</div>
|
||||
<div class="ts segment">
|
||||
<i class="inbox icon"></i>牌組 <span id="selfDeck">--</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Log -->
|
||||
<div class="four wide column">
|
||||
<label>Log</label>
|
||||
<div class="ts speeches" id="log">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card Container -->
|
||||
<div class="ts fluid container" style="position: absolute; bottom:0;">
|
||||
<label>你的手牌</label>
|
||||
<div class="cards container">
|
||||
<a class="ts card"><div class="content"><div class="header">Waiting</div><div class="meta">0</div><div class="description">等待中</div></div></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Anchor -->
|
||||
<!-- snackbar -->
|
||||
<div class="ts bottom right snackbar">
|
||||
<div class="content"></div>
|
||||
<a class="action"></a>
|
||||
</div>
|
||||
<!-- modal -->
|
||||
<div class="ts modals dimmer">
|
||||
<dialog id="modal" class="ts modal">
|
||||
<div class="header"></div>
|
||||
<div class="content"></div>
|
||||
<div class="actions"></div>
|
||||
</dialog>
|
||||
</div>
|
||||
</body>
|
||||
<!-- websocket util -->
|
||||
<script src="./ws.js"></script>
|
||||
<!-- string formating util -->
|
||||
<script src="./stringFormat.js"></script>
|
||||
<!-- game core -->
|
||||
<script src="./gameCore.js"></script>
|
||||
</html>
|
696
web/gameCore.js
Normal file
696
web/gameCore.js
Normal file
@ -0,0 +1,696 @@
|
||||
/* System Variable */
|
||||
var time,timer;
|
||||
var MouseOn = false;
|
||||
var now = null; // to store whose turn is this. value: "player" or "enemy"
|
||||
var socketReady = false;
|
||||
var lock = true;
|
||||
var debugMode = true;
|
||||
var dialogDisplay = false;
|
||||
var curName = "";
|
||||
var eneName = "";
|
||||
var drawID = "";
|
||||
var poisonDamage = "";
|
||||
var tradeChoose = "";
|
||||
var handCards = [];
|
||||
|
||||
/* DOM Objects */
|
||||
var cardContainer = $('.cards.container')[0];
|
||||
var dialog = $('#modal');
|
||||
var grid = $('#grid')[0];
|
||||
var column = $('.column');
|
||||
var log = $('#log')[0];
|
||||
var gameStatus = $('#status');
|
||||
var turn = $('#turn')[0];
|
||||
var roomNum = $('.statistic > .value')[0];
|
||||
|
||||
var enemy = $('#enemy');
|
||||
var myself = $('#myself');
|
||||
|
||||
/* text */
|
||||
// cards
|
||||
var cards = {'1': '攻擊', '2': '防禦', '3': '治癒', '4': '補給', '5': '強奪', '6': '奇襲', '7': '交易', '8': '洞悉', '9': '妙策', '10': '掃射', '11': '加護', '12': '劇毒', '13': '詛咒', '14': '反制', '15': '狂亂', '16': '逆轉'};
|
||||
var cardsDescription = {"1":"對敵方造成兩點傷害","2":"回復一點生命<br>被動:抵擋攻擊類卡片","3":"回復兩點生命","4":"抽取兩張手牌","5":"從敵方手牌中選擇一張加入自己的手牌","6":"對敵方造成兩點傷害,並使其隨機損失一張手牌","7":"選取一張手牌與敵方交換","8":"抽取三張手牌<br>被動:抵擋攻擊類卡片,並抽取一張手牌、抵擋強奪的效果","9":"從牌庫中隨機挑出三張卡片,選擇一張加入手牌","10":"對敵方造成零~五點傷害","11":"回復三點生命,並解除中毒","12":"使敵方中毒:每個回合,玩家會損失一點生命","13":"使其損失四點生命,並隨機損失一張手牌","14":"使敵方生命減半<br>被動:抵擋攻擊類卡片,並反彈其傷害和效果","15":"回復三點生命,並對敵方造成三點傷害","16":"使自己與敵方的生命交換"}
|
||||
|
||||
var characters = {'1': '安', '2': '圭月', '3': '梅', '4': '小兔', '5': '銀', '6': '正作', '7': 'W', '8': '桑德', '9': '海爾', '10': '雪村'};
|
||||
|
||||
// templates
|
||||
var cardTemplate = `<a class="ts card" data-id="{{ id }}"><div class="content"><div class="header">{{ name }}</div><div class="meta">{{ id }}</div><div class="description">{{ description }}</div></div></a>`;
|
||||
var listCardTemplate = `<div class="disabled item" data-id="{{ id }}"><div class="ts header">{{ name }}<div class="sub header">{{ description }}</div></div></div>`;
|
||||
var logTemplate = `<div class="{{ isSelf }} speech"><div class="content">{{ content }}</div></div>`;
|
||||
var logDivider = `<div class="ts horizontal divider">{{ player }} Turn {{ turn }}</div>`;
|
||||
|
||||
// messages
|
||||
var messages = {
|
||||
"attack": "{} 攻擊 {}",
|
||||
"damaged": "{} 受到{}點傷害",
|
||||
"defended": "{} 防禦成功",
|
||||
"defend": "{} 沒什麼可以防禦的,回復一點生命",
|
||||
"heal": "{} 回復兩點生命",
|
||||
"supply": "{} 增加兩張手牌",
|
||||
"rob": "{} 正在對 {} 行搶",
|
||||
"cantRob": "{}沒有搶到任何東西",
|
||||
"robbed": "{} 搶到了 {}",
|
||||
"surprise": "{} 發動奇襲",
|
||||
"surprised": "{} 受到{}點傷害,而且掉了一張手牌",
|
||||
"surNoCard": "{} 受到{}點傷害",
|
||||
"trade": "{} 想與 {} 進行交易",
|
||||
"tradeChoose": "{} 選擇了 {}",
|
||||
"tradeNoCard": "{} 沒有卡片可以交易",
|
||||
"awared": "{} 洞悉了 {} 的{},並抽取了一張手牌",
|
||||
"aware": "{} 增加三張手牌",
|
||||
"plan": "{} 有個妙策",
|
||||
"sweep": "{} 對 {} 進行掃射,威力是 {}",
|
||||
"bless": "{} 獲得加護,身上的毒素一掃而空,並回復三點生命,還抽取了兩張手牌",
|
||||
"poison": "{} 在食物下毒,{}中毒了",
|
||||
"curse": "{} 詛咒了 {},使其損失四點生命,並掉了一張手牌",
|
||||
"curseNoCard": "{} 詛咒了 {},使其損失四點生命",
|
||||
"countered": "{} 反制了 {} 的攻擊,反彈了{}點傷害",
|
||||
"counteredSur": "{} 反制了 {} 的攻擊,反彈了{}點傷害,並使其掉了一張手牌",
|
||||
"counter": "{} 反制了敵手,使 {} 生命值減半了!",
|
||||
"chaos": "{} 進入狂亂模式,回復三點生命,並對 {} 造成三點傷害",
|
||||
"reverse": "{} 一口氣逆轉了情勢",
|
||||
"noCard": "你抽到了死神",
|
||||
"poisonDamaged": "{} 受到了劇毒的侵蝕,損失{}點生命",
|
||||
"surrender": "{}投降",
|
||||
"firstAttack": "{}先攻",
|
||||
"win": "{}獲勝",
|
||||
"draw": "{}抽到了{}",
|
||||
"drawEne": "{}抽了一張卡片",
|
||||
"use": "{}使用了{}",
|
||||
"eneDisconn": "因敵方斷線,所以{}獲勝"
|
||||
};
|
||||
/* text end */
|
||||
|
||||
// handler
|
||||
function wsHandler(dataJson) {
|
||||
if (debugMode) { // debugging data
|
||||
rawLog(dataJson);
|
||||
}
|
||||
// define the current player and update player status
|
||||
if (dataJson.now === "player") {
|
||||
now = "player";
|
||||
gameUpdate(dataJson);
|
||||
$('#skip').removeClass('disabled');
|
||||
} else if (dataJson.now === "enemy") {
|
||||
now = "enemy";
|
||||
gameUpdate(dataJson);
|
||||
$('#skip').addClass('disabled');
|
||||
}
|
||||
/* special cases */
|
||||
if (dataJson.toString().match(/^[0-9]{1,5}$/)) { // contains only number => room id
|
||||
id = dataJson.toString();
|
||||
gameUpdate({ "room": id });
|
||||
return null;
|
||||
}
|
||||
if (dataJson.room) { // game start
|
||||
curName = dataJson['cur'];
|
||||
eneName = dataJson['ene'];
|
||||
setPlayerName(curName);
|
||||
setEnemyName(eneName);
|
||||
$('#enemy .icon').css('opacity','1'); // show enemy avatar
|
||||
return null;
|
||||
}
|
||||
if (dataJson.action) { // time for users to do more action!
|
||||
// Received: {"msg": "rob", "data": ["W", "\u96ea\u6751"], "action": "toRob", "value": {"enemy_card": ["5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5"]}}
|
||||
statusInitialize();
|
||||
lock = false;
|
||||
switch (dataJson.action) {
|
||||
case "toDefend":
|
||||
askGuard(dataJson.value);
|
||||
break;
|
||||
case "toRob":
|
||||
chooseRob(dataJson.value['enemy_card']);
|
||||
break;
|
||||
case "toBeRobbed":
|
||||
askDefendRob();
|
||||
break;
|
||||
case "toTrade":
|
||||
if (dataJson.value) {
|
||||
chooseTrade(dataJson.value['hand'])
|
||||
} else {
|
||||
chooseTrade(handCards,tradeChoose);
|
||||
}
|
||||
break;
|
||||
case "toAdd":
|
||||
choosePlan(dataJson.value['cards']);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// normal situation
|
||||
if (dataJson.msg) {
|
||||
switch (dataJson.msg) {
|
||||
case "draw":
|
||||
drawID = dataJson.data[1]; // card ID
|
||||
break;
|
||||
case "use":
|
||||
useID = dataJson.data[1]; // card ID
|
||||
dataJson.data[1] = cards[useID]; // edit data
|
||||
Log(dataJson);
|
||||
break;
|
||||
case "robbed":
|
||||
robbedCard = dataJson.data[1]; // card ID
|
||||
LogPlayerChoose("robbed",robbedCard);
|
||||
break;
|
||||
case "tradeChoose":
|
||||
tradeChoose = dataJson.data[1]; // card ID
|
||||
LogPlayerChoose("tradeChoose",tradeChoose);
|
||||
break;
|
||||
case "poisonDamaged":
|
||||
poisonDamage = dataJson.data[1]; // posion level
|
||||
break;
|
||||
case "win":
|
||||
if (dataJson.data[0] === "player") {
|
||||
playerWin();
|
||||
dataJson.data[0] = '你';
|
||||
Log(dataJson);
|
||||
} else if (dataJson.data[0] === "enemy") {
|
||||
playerLose();
|
||||
}
|
||||
break;
|
||||
case "eneDisconn":
|
||||
playerWin();
|
||||
Log(dataJson);
|
||||
break;
|
||||
default:
|
||||
Log(dataJson);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function wsOnClose() {
|
||||
console.log("Disconnected");
|
||||
ts('.snackbar').snackbar({
|
||||
content: '已中斷連線',
|
||||
});
|
||||
statusInitialize();
|
||||
gameStatus.html('連線已中斷');
|
||||
gameStatus.addClass('warning');
|
||||
$('#skip').addClass('disabled');
|
||||
$('#giveup').addClass('disabled');
|
||||
unsetCardListener();
|
||||
socketReady = false;
|
||||
}
|
||||
|
||||
function wsOnOpen(status) {
|
||||
console.log("Connected! Status:" + status);
|
||||
ts('.snackbar').snackbar({
|
||||
content: '連線成功!'
|
||||
});
|
||||
socketReady = true;
|
||||
}
|
||||
|
||||
function wsOnError(except) {
|
||||
ts('.snackbar').snackbar({
|
||||
content: '連線失敗!',
|
||||
action: '重試',
|
||||
actionEmphasis: 'negative',
|
||||
onAction: () => {
|
||||
init();
|
||||
}
|
||||
});
|
||||
console.log(except);
|
||||
} // https://stackoverflow.com/questions/25779831/how-to-catch-websocket-connection-to-ws-xxxnn-failed-connection-closed-be
|
||||
|
||||
// listener
|
||||
function setCardListener() {
|
||||
$('.cards.container a.ts.card').each((i,e) => {
|
||||
$(e).click(function() {
|
||||
useCard(this.dataset.id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function unsetCardListener() {
|
||||
$('.cards.container a.ts.card').each((i,e) => {
|
||||
$(e).off("click");
|
||||
});
|
||||
}
|
||||
|
||||
function setModalCardListListener() {
|
||||
$('#modal .ts.list .item').each((i,e) => {
|
||||
$(e).click(function() {
|
||||
useCard(this.dataset.id);
|
||||
modalClose();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setModalSkipButtonListener() {
|
||||
$('#modal #modalSkipBtn').click(function() {
|
||||
send(0);
|
||||
modalClose();
|
||||
});
|
||||
}
|
||||
|
||||
$('#skip').click(function() {
|
||||
if (!$(this).hasClass('disabled')) {
|
||||
send(0);
|
||||
}
|
||||
});
|
||||
|
||||
$('#giveup').click(function() {
|
||||
quit();
|
||||
});
|
||||
|
||||
function resultListener() {
|
||||
$('#returnIndex').click(function() {
|
||||
location.href = './index.html';
|
||||
});
|
||||
$('#restart').click(function() {
|
||||
location.reload();
|
||||
});
|
||||
$('#close').click(function() {
|
||||
modalClose();
|
||||
});
|
||||
}
|
||||
|
||||
// log
|
||||
log.addEventListener("mouseover", function() { MouseOn = true; }); // if mouse is over the div, don't scroll to bottom
|
||||
log.addEventListener("mouseleave", function() { MouseOn = false; });
|
||||
|
||||
function Log(msgJson) {
|
||||
var node = logTemplate;
|
||||
if(now === "player") { // to distinguish if this is self log or enemy log
|
||||
node = node.replace("{{ isSelf }}","right");
|
||||
} else if (now === "enemy") {
|
||||
node = node.replace("{{ isSelf }}","");
|
||||
}
|
||||
|
||||
node = node.replace("{{ content }}",messages[msgJson['msg']].format(msgJson['data']));
|
||||
log.insertAdjacentHTML("beforeend",node); // insert to log
|
||||
if (!MouseOn) { // if mouse isn't over the div, scroll to bottom
|
||||
log.scrollTop = log.scrollHeight; // scroll to bottom
|
||||
}
|
||||
}
|
||||
|
||||
function LogPlayerDraw() {
|
||||
var node = logTemplate.replace("{{ isSelf }}","right");
|
||||
node = node.replace("{{ content }}",messages['draw'].format([curName,cards[drawID]])); // msgJson['data'][0] player name, msgJson['data'][1] card id
|
||||
log.insertAdjacentHTML("beforeend",node); // insert to log
|
||||
if (!MouseOn) { // if mouse isn't over the div, scroll to bottom
|
||||
log.scrollTop = log.scrollHeight; // scroll to bottom
|
||||
}
|
||||
drawID = "";
|
||||
}
|
||||
|
||||
function LogPlayerChoose(type,dataID) {
|
||||
var node = logTemplate.replace("{{ isSelf }}","right");
|
||||
var tmpName = "";
|
||||
if(now === "player") { // to distinguish if this is self log or enemy log
|
||||
node = node.replace("{{ isSelf }}","right");
|
||||
tmpName = curName;
|
||||
} else if (now === "enemy") {
|
||||
node = node.replace("{{ isSelf }}","");
|
||||
tmpName = eneName;
|
||||
}
|
||||
node = node.replace("{{ content }}",messages[type].format([tmpName,cards[dataID]])); // msgJson['data'][0] player name, msgJson['data'][1] card id
|
||||
log.insertAdjacentHTML("beforeend",node); // insert to log
|
||||
if (!MouseOn) { // if mouse isn't over the div, scroll to bottom
|
||||
log.scrollTop = log.scrollHeight; // scroll to bottom
|
||||
}
|
||||
}
|
||||
|
||||
function LogPlayerPoisonDamaged() {
|
||||
var node = logTemplate;
|
||||
var tmpName = "";
|
||||
if(now === "player") { // to distinguish if this is self log or enemy log
|
||||
node = node.replace("{{ isSelf }}","right");
|
||||
tmpName = curName;
|
||||
} else if (now === "enemy") {
|
||||
node = node.replace("{{ isSelf }}","");
|
||||
tmpName = eneName;
|
||||
}
|
||||
node = node.replace("{{ content }}",messages['poisonDamaged'].format([tmpName,poisonDamage])); // msgJson['data'][0] player name, msgJson['data'][1] card id
|
||||
log.insertAdjacentHTML("beforeend",node); // insert to log
|
||||
if (!MouseOn) { // if mouse isn't over the div, scroll to bottom
|
||||
log.scrollTop = log.scrollHeight; // scroll to bottom
|
||||
}
|
||||
poisonDamage = "";
|
||||
}
|
||||
|
||||
function rawLog(msg) {
|
||||
console.log(JSON.stringify(msg));
|
||||
if (!MouseOn) { // if mouse isn't over the div, scroll to bottom
|
||||
log.scrollTop = log.scrollHeight; // scroll to bottom
|
||||
}
|
||||
}
|
||||
|
||||
function logTurn(playerName,playerTurn) {
|
||||
var node = logDivider;
|
||||
node = node.replace("{{ player }}",playerName);
|
||||
node = node.replace("{{ turn }}",playerTurn);
|
||||
log.insertAdjacentHTML("beforeend",node); // insert to log
|
||||
if (!MouseOn) { // if mouse isn't over the div, scroll to bottom
|
||||
log.scrollTop = log.scrollHeight; // scroll to bottom
|
||||
}
|
||||
}
|
||||
|
||||
// game status updater
|
||||
function gameUpdate(data) {
|
||||
if (data.room) {
|
||||
roomNum.innerHTML = data.room.padStart(5,'0');
|
||||
} else if (data.now) {
|
||||
if (data.now === "player") {
|
||||
turn.innerHTML = curName+" Turn "+data.player.turn;
|
||||
logTurn(curName,data.player.turn);
|
||||
if (drawID !== "") {
|
||||
LogPlayerDraw(data);
|
||||
}
|
||||
statusInitialize();
|
||||
lock = false; // unlock the cards
|
||||
gameStatus.addClass('primary');
|
||||
gameStatus.html('輪到你出牌');
|
||||
timerSetup(28);
|
||||
} else if (data.now === "enemy") {
|
||||
turn.innerHTML = eneName+" Turn "+data.enemy.turn;
|
||||
logTurn(eneName,data.enemy.turn);
|
||||
statusInitialize();
|
||||
gameStatus.html('等待對手出牌');
|
||||
}
|
||||
if (poisonDamage !== "") {
|
||||
LogPlayerPoisonDamaged();
|
||||
}
|
||||
playerUpdate(data['player']);
|
||||
enemyUpdate(data['enemy']);
|
||||
modalClose();
|
||||
}
|
||||
}
|
||||
|
||||
function statusInitialize() {
|
||||
gameStatus.removeClass('info negative warning pulsing primary inverted'); // initailize the status
|
||||
timerInitialize();
|
||||
}
|
||||
|
||||
// player status updater
|
||||
function setPlayerName(name) {
|
||||
var selfNameHeader = $('#myself > .profile > .name > .header');
|
||||
selfNameHeader.html(name);
|
||||
}
|
||||
|
||||
function setEnemyName(name) {
|
||||
var eneNameHeader = $('#enemy > .profile > .name > .header');
|
||||
eneNameHeader.html(name);
|
||||
}
|
||||
|
||||
function playerUpdate(data) {
|
||||
handCards = data['hand'];
|
||||
setCard(data['hand']);
|
||||
var selfHand = $('#selfHand'); // 手牌數
|
||||
var selfDeck = $('#selfDeck');
|
||||
var selfLifeBar = $('#myself > .profile > .life.progress > .bar');
|
||||
var selfLifeText = selfLifeBar.children();
|
||||
var selfStatus = $('#myself > .profile > .status');
|
||||
var barWidth = (parseInt(data['life'])/20)*100 // %
|
||||
selfHand.html(data['hand'].length);
|
||||
selfDeck.html(data['deck_left']);
|
||||
selfLifeBar.css('width',barWidth+'%');
|
||||
selfLifeBar.attr('data-life',data['life']);
|
||||
selfLifeText.html(data['life']);
|
||||
if (parseInt(data['poison']) > 0){
|
||||
selfStatus.html('<p class="poison"><i class="theme icon"></i> 中毒 lv.'+data['poison']+'</p>');
|
||||
selfLifeBar.addClass('poison');
|
||||
} else if (parseInt(data['poison']) == 0) {
|
||||
if (selfLifeBar.hasClass('poison')) {
|
||||
selfLifeBar.removeClass('poison');
|
||||
}
|
||||
selfStatus.html('清新');
|
||||
}
|
||||
|
||||
if (parseInt(data['life']) <= 0) { // dead
|
||||
if (selfLifeBar.hasClass('poison')) {
|
||||
selfLifeBar.removeClass('poison');
|
||||
}
|
||||
selfLifeBar.addClass('negative');
|
||||
}
|
||||
}
|
||||
|
||||
function enemyUpdate(data) {
|
||||
var eneHand = $('#eneHand'); // 手牌數
|
||||
var eneDeck = $('#eneDeck');
|
||||
var eneLifeBar = $('#enemy > .profile > .life.progress > .bar');
|
||||
var eneLifeText = eneLifeBar.children();
|
||||
var eneStatus = $('#enemy > .profile > .status');
|
||||
var barWidth = (parseInt(data['life'])/20)*100 // %
|
||||
eneHand.html(data['hand']);
|
||||
eneDeck.html(data['deck_left']);
|
||||
eneLifeBar.css('width',barWidth+'%');
|
||||
eneLifeBar.attr('data-life',data['life']);
|
||||
eneLifeText.html(data['life']);
|
||||
if (parseInt(data['poison']) > 0){
|
||||
eneStatus.html('<p class="poison"><i class="theme icon"></i> 中毒 lv.'+data['poison']+'</p>');
|
||||
eneLifeBar.addClass('poison');
|
||||
} else if (parseInt(data['poison']) == 0) {
|
||||
if (eneLifeBar.hasClass('poison')) {
|
||||
eneLifeBar.removeClass('poison');
|
||||
}
|
||||
eneStatus.html('清新');
|
||||
}
|
||||
|
||||
if (parseInt(data['life']) <= 0) { // dead
|
||||
if (eneLifeBar.hasClass('poison')) {
|
||||
eneLifeBar.removeClass('poison');
|
||||
}
|
||||
eneLifeBar.addClass('negative');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// card
|
||||
function useCard(id) {
|
||||
if (!lock) {
|
||||
statusInitialize();
|
||||
send(id);
|
||||
lock = true;
|
||||
}
|
||||
}
|
||||
|
||||
function setCard(cardsArray) {
|
||||
$(cardContainer).empty();
|
||||
var node = "";
|
||||
cardsArray.forEach((id) => {
|
||||
var tmp = cardTemplate;
|
||||
tmp = tmp.replace(/{{ id }}/g,id).replace("{{ name }}",cards[id]).replace("{{ description }}",cardsDescription[id]);
|
||||
node += tmp;
|
||||
});
|
||||
$(cardContainer).append(node);
|
||||
setCardListener();
|
||||
resize(); // special case
|
||||
}
|
||||
|
||||
// modals
|
||||
function chooseRob(data) {
|
||||
var list = `<div class="ts selection segmented list">`;
|
||||
data.forEach((id) => {
|
||||
var tmp = listCardTemplate;
|
||||
tmp = tmp.replace('disabled','').replace('{{ id }}',id).replace("{{ name }}",cards[id]).replace("{{ description }}",cardsDescription[id]);
|
||||
list+=tmp;
|
||||
});
|
||||
list+='</div>';
|
||||
dialog.children(".header").html('請問要搶哪張?');
|
||||
dialog.children(".content").html(list);
|
||||
dialog.children(".actions").html('');
|
||||
setModalCardListListener();
|
||||
modalOpen();
|
||||
}
|
||||
|
||||
function chooseTrade(data,tradeID=null) {
|
||||
console.log(tradeChoose);
|
||||
if (tradeID) {
|
||||
var text = "<p>對手選擇了"+cards[tradeID]+"</p>";
|
||||
} else {
|
||||
var text = "<p>選擇一張卡與對手交換</p>";
|
||||
}
|
||||
var list = `<div class="ts selection segmented list">`;
|
||||
data.forEach((id) => {
|
||||
var tmp = listCardTemplate;
|
||||
tmp = tmp.replace('disabled','').replace('{{ id }}',id).replace("{{ name }}",cards[id]).replace("{{ description }}",cardsDescription[id]);
|
||||
list+=tmp;
|
||||
});
|
||||
list+='</div>';
|
||||
dialog.children(".header").html('交易')
|
||||
dialog.children(".content").html(text+list);
|
||||
dialog.children(".actions").html('');
|
||||
setModalCardListListener();
|
||||
modalOpen();
|
||||
tradeChoose = ""; // reset value
|
||||
}
|
||||
|
||||
function choosePlan(data) {
|
||||
var text = `<p>請從三張卡中選擇一張加入手牌</p>`;
|
||||
var list = `<div class="ts selection segmented list">`;
|
||||
data.forEach((id) => {
|
||||
var tmp = listCardTemplate;
|
||||
tmp = tmp.replace('disabled','').replace('{{ id }}',id).replace("{{ name }}",cards[id]).replace("{{ description }}",cardsDescription[id]); // not need to be disabled
|
||||
list+=tmp;
|
||||
});
|
||||
list+='</div>';
|
||||
dialog.children(".header").html('妙策');
|
||||
dialog.children(".content").html(text+list);
|
||||
dialog.children(".actions").html('');
|
||||
setModalCardListListener();
|
||||
modalOpen();
|
||||
}
|
||||
|
||||
function askGuard(data) {
|
||||
var attackType = data['type'];
|
||||
var attackName = {"attack": "攻擊","surprise": "奇襲","sweep": "掃射"};
|
||||
var damage = data['damage'];
|
||||
var text = `對手使用了 `+attackName[attackType]+`,傷害為 `+damage;
|
||||
var list = `<div class="ts selection segmented list">`;
|
||||
handCards.forEach((id) => {
|
||||
var tmp = listCardTemplate;
|
||||
tmp = tmp.replace('{{ id }}',id).replace("{{ name }}",cards[id]).replace("{{ description }}",cardsDescription[id]);
|
||||
list+=tmp;
|
||||
});
|
||||
list+='</div>';
|
||||
dialog.children(".header").html('防禦');
|
||||
dialog.children(".content").html(text+list);
|
||||
dialog.children(".actions").html('<button id="modalSkipBtn" class="ts primary button">不使用卡片</button>');
|
||||
setModalCardListListener();
|
||||
setModalSkipButtonListener();
|
||||
$('#modal .ts.list .item').each((i,e) => {
|
||||
if (e.dataset.id == "2" || e.dataset.id == "8" || e.dataset.id == "14") {
|
||||
$(e).removeClass('disabled');
|
||||
}
|
||||
});
|
||||
modalOpen();
|
||||
}
|
||||
|
||||
function askDefendRob() {
|
||||
var list = `<div class="ts selection segmented list">`;
|
||||
handCards.forEach((id) => {
|
||||
var tmp = listCardTemplate;
|
||||
tmp = tmp.replace('{{ id }}',id).replace("{{ name }}",cards[id]).replace("{{ description }}",cardsDescription[id]);
|
||||
list+=tmp;
|
||||
});
|
||||
list+='</div>';
|
||||
dialog.children(".header").html('防禦強奪');
|
||||
dialog.children(".content").html(list);
|
||||
dialog.children(".actions").html('<button id="modalSkipBtn" class="ts primary button">不使用卡片</button>');
|
||||
setModalCardListListener();
|
||||
setModalSkipButtonListener();
|
||||
$('#modal .ts.list .item').each((i,e) => {
|
||||
if (e.dataset.id == "8") {
|
||||
$(e).removeClass('disabled');
|
||||
}
|
||||
});
|
||||
modalOpen();
|
||||
}
|
||||
|
||||
function playerWin() {
|
||||
dialog.children(".header").html('你贏了!');
|
||||
dialog.children(".content").html('<img src="./won.png"><p class="result enemy name">'+eneName+'</p><p class="result player name">'+curName+'</p>');
|
||||
dialog.children(".actions").html('<button id="close" class="ts button">關閉視窗</button><button id="restart" class="ts primary button">重啟對戰</button><button id="returnIndex" class="ts positive button">返回主畫面</button>');
|
||||
timerInitialize(); // also remember to stop the timer
|
||||
modalOpen();
|
||||
resultListener();
|
||||
}
|
||||
|
||||
function playerLose() {
|
||||
dialog.children(".header").html('你輸爆了,SAD');
|
||||
dialog.children(".content").html('<img src="./lose.png"><p class="result enemy name">'+eneName+'</p><p class="result player name">'+curName+'</p>');
|
||||
dialog.children(".actions").html('<button id="close" class="ts button">關閉視窗</button><button id="restart" class="ts primary button">重啟對戰</button><button id="returnIndex" class="ts positive button">返回主畫面</button>');
|
||||
timerInitialize(); // also remember to stop the timer
|
||||
modalOpen();
|
||||
resultListener();
|
||||
}
|
||||
|
||||
function modalClose() {
|
||||
if (dialogDisplay) {
|
||||
ts('#modal').modal('hide');
|
||||
console.log('close');
|
||||
dialogDisplay = false;
|
||||
}
|
||||
}
|
||||
|
||||
function modalOpen() {
|
||||
if (!dialogDisplay) {
|
||||
ts('#modal').modal('show');
|
||||
console.log('open');
|
||||
dialogDisplay = true;
|
||||
}
|
||||
}
|
||||
|
||||
// countdown timer for each turn
|
||||
function timing() {
|
||||
if (time == 0) {
|
||||
clearInterval(timer); // unset the timer
|
||||
gameStatus.removeClass('warning pulsing');
|
||||
gameStatus.addClass('negative');
|
||||
gameStatus.text('時間到!');
|
||||
return null;
|
||||
}
|
||||
if (time <= 5) {
|
||||
if(!gameStatus.hasClass('pulsing')) {
|
||||
gameStatus.addClass('pulsing'); // pulsing animation
|
||||
}
|
||||
gameStatus.removeClass('info');
|
||||
gameStatus.addClass('warning');
|
||||
gameStatus.text('輪到你出牌 '+time);
|
||||
} else if (time <= 10) {
|
||||
if(!gameStatus.hasClass('pulsing')) {
|
||||
gameStatus.addClass('pulsing'); // pulsing animation
|
||||
}
|
||||
gameStatus.text('輪到你出牌 '+time);
|
||||
} else {
|
||||
gameStatus.removeClass('negative pulsing');
|
||||
gameStatus.addClass('info');
|
||||
gameStatus.text('輪到你出牌');
|
||||
}
|
||||
time--;
|
||||
}
|
||||
|
||||
function timerSetup(t) {
|
||||
time = t;
|
||||
timer = setInterval(timing,1000);
|
||||
}
|
||||
|
||||
function timerInitialize() {
|
||||
clearInterval(timer);
|
||||
gameStatus.addClass('inverted');
|
||||
gameStatus.html('等待中');
|
||||
}
|
||||
|
||||
// resize
|
||||
function resize() {
|
||||
var h = cardContainer.offsetHeight;
|
||||
grid.style.height='calc(100vh - ' + h + 'px)';
|
||||
column.css('height','calc(100vh - ' + h + 'px)');
|
||||
}
|
||||
|
||||
resize();
|
||||
window.addEventListener("resize",resize);
|
||||
|
||||
// game initailize
|
||||
$(document).ready(() => {
|
||||
var roomID = localStorage.getItem('room');
|
||||
var characterID = localStorage.getItem('character');
|
||||
if(!roomID || !characterID){
|
||||
roomID = "n";
|
||||
characterID = "1"; // default charactor
|
||||
}
|
||||
setPlayerName(characters[characterID]);
|
||||
init();
|
||||
var retry = setInterval(() => {
|
||||
if(socketReady) { // send the charactor id and room id until the connected
|
||||
send(characterID);
|
||||
send(roomID);
|
||||
clearInterval(retry);
|
||||
}
|
||||
}, 300); // try every 0.3s
|
||||
});
|
||||
|
||||
/* https://stackoverflow.com/questions/11700927/horizontal-scrolling-with-mouse-wheel-in-a-div */
|
||||
function scrollHorizontally(e) {
|
||||
e = window.event || e;
|
||||
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
|
||||
cardContainer.scrollLeft -= (delta*40); // Multiplied by 40
|
||||
e.preventDefault();
|
||||
}
|
||||
cardContainer.addEventListener("mousewheel", scrollHorizontally, false);
|
||||
cardContainer.addEventListener("DOMMouseScroll", scrollHorizontally, false); //Firefox
|
88
web/gameUI.css
Normal file
88
web/gameUI.css
Normal file
@ -0,0 +1,88 @@
|
||||
.cards.container > .ts.card {
|
||||
width: 220px !important;
|
||||
display: inline-flex !important;
|
||||
white-space: normal;
|
||||
margin-left: 8px;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.cards.container > .ts.card:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
.cards.container {
|
||||
overflow-x: scroll;
|
||||
white-space: nowrap;
|
||||
min-height: 140px;
|
||||
width: 100%;
|
||||
padding : 0 8px;
|
||||
background-color: rgb(250,250,250);
|
||||
}
|
||||
body,html {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
label {
|
||||
background-color: black;
|
||||
color: white;
|
||||
opacity: 0.6;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: 5px 10px;
|
||||
z-index: 10;
|
||||
}
|
||||
.grid,.column {
|
||||
height: unset;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
.speeches {
|
||||
overflow-y: scroll;
|
||||
height: 100%;
|
||||
padding: 10px 5px;
|
||||
box-sizing: border-box;
|
||||
border-left: 1px solid rgba(0,0,0,0.2);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.2);
|
||||
background-color: #efeef1;
|
||||
}
|
||||
#game,#myself,#enemy {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
#game > *,#enemy > *,#myself > * {
|
||||
margin: auto;
|
||||
}
|
||||
.ts.progress .bar {
|
||||
min-width: 20px;
|
||||
}
|
||||
.poison {
|
||||
color: purple !important;
|
||||
}
|
||||
.poison.bar {
|
||||
background-color: purple !important;
|
||||
}
|
||||
.bar {
|
||||
transition: width .5s ease-in-out;
|
||||
}
|
||||
.modal .list{
|
||||
max-height: 60vh;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.modal .content img {
|
||||
width: 100%;
|
||||
}
|
||||
p.result.name {
|
||||
position: absolute;
|
||||
font-size:50px;
|
||||
top: calc(50% - 25px);
|
||||
margin: 0;
|
||||
line-height: 50px;
|
||||
}
|
||||
p.result.enemy.name {
|
||||
left: 1.5em;
|
||||
}
|
||||
p.result.player.name {
|
||||
right: 1.5em;
|
||||
}
|
81
web/index.html
Normal file
81
web/index.html
Normal file
@ -0,0 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>災厄之悲歌</title>
|
||||
<!-- Tocas UI:CSS 與元件 -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocas-ui/2.3.3/tocas.css">
|
||||
<!-- Tocas JS:模塊與 JavaScript 函式 -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocas-ui/2.3.3/tocas.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
body > .container {
|
||||
height: 100%;
|
||||
}
|
||||
.title.container {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
.dialog.container {
|
||||
display: flex !important;
|
||||
flex-direction: column;
|
||||
}
|
||||
.dialog.container > .ts.segment {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="ts title fluid center aligned container">
|
||||
<h1 style="margin-left: auto; margin-right: auto;display: inline-flex;">災厄之悲歌</h1>
|
||||
<button class="ts primary animated fadeInDown button" style="animation-delay: .8s;">進入遊戲</button>
|
||||
<div class="ts steps" style="display: none;">
|
||||
<a class="step" id="firstStep">
|
||||
<i class="user icon"></i>
|
||||
<div class="content">
|
||||
<div class="title">角色</div>
|
||||
<div class="description">選擇你的鬥士</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="step" id="secondStep">
|
||||
<i class="cube icon"></i>
|
||||
<div class="content">
|
||||
<div class="title">房號</div>
|
||||
<div class="description">輸入房號,或是隨機加入遊戲</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="ts segment" id="character" style="display: none;">
|
||||
<div class="ts big centered menu">
|
||||
<a class="item" data-id="1">安</a>
|
||||
<a class="item" data-id="2">圭月</a>
|
||||
<a class="item" data-id="3">梅</a>
|
||||
<a class="item" data-id="4">小兔</a>
|
||||
<a class="item" data-id="5">銀</a>
|
||||
<a class="item" data-id="6">正作</a>
|
||||
<a class="item" data-id="7">W</a>
|
||||
<a class="item" data-id="8">桑德</a>
|
||||
<a class="item" data-id="9">海爾</a>
|
||||
<a class="item" data-id="10">雪村</a>
|
||||
</div>
|
||||
<button id="next" class="ts positive button">確認</button>
|
||||
</div>
|
||||
<div class="ts segment" id="room" style="display: none;">
|
||||
<div class="ts action input">
|
||||
<input id="roomNum" type="text" placeholder="0~99999">
|
||||
<button id="roomBtn" class="ts positive button">Join!</button>
|
||||
</div>
|
||||
<div class="ts horizontal divider">or</div>
|
||||
<button id="random" class="ts primary button">隨機配對</button>
|
||||
</div>
|
||||
<script src="./menu.js"></script>
|
||||
</body>
|
||||
</html>
|
BIN
web/lose.png
Normal file
BIN
web/lose.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
92
web/menu.js
Normal file
92
web/menu.js
Normal file
@ -0,0 +1,92 @@
|
||||
// value setter
|
||||
var roomID = null,
|
||||
characterID = null;
|
||||
|
||||
function setter() {
|
||||
if(characterID && roomID){
|
||||
localStorage.setItem('character',characterID);
|
||||
localStorage.setItem('room',roomID);
|
||||
}
|
||||
}
|
||||
// listener
|
||||
var btn = document.querySelector('.ts.primary.button');
|
||||
btn.addEventListener('click',() => {
|
||||
btn.classList.remove('fadeInDown');
|
||||
btn.style.animationDelay = "0s";
|
||||
btn.classList.add('fadeOutUp');
|
||||
setTimeout(() => {displayCharacter();},800)
|
||||
});
|
||||
|
||||
var characterMenu = document.querySelector('.ts.centered.menu');
|
||||
var characters = Array.from(characterMenu.children);
|
||||
characterMenu.addEventListener('click', (e) => {
|
||||
var id = e.target.dataset.id;
|
||||
console.log("charactor:"+id);
|
||||
if(id) {
|
||||
characters.forEach(e => {
|
||||
e.classList.remove('active');
|
||||
});
|
||||
characterID = id;
|
||||
e.target.classList.add('active');
|
||||
}
|
||||
});
|
||||
|
||||
var nextBtn = document.querySelector('#next');
|
||||
nextBtn.addEventListener('click',() => { displayRoom() });
|
||||
|
||||
var firstStep = document.querySelector('#firstStep');
|
||||
firstStep.addEventListener('click',() => { displayCharacter() });
|
||||
|
||||
var roomNum = document.querySelector('#roomNum');
|
||||
var roomBtn = document.querySelector('#roomBtn');
|
||||
roomBtn.addEventListener('click',() => {
|
||||
if(roomNum.value != null && 0 <= parseInt(roomNum.value) && 99999 >= parseInt(roomNum.value)){
|
||||
console.log('room:'+roomNum.value)
|
||||
roomID = roomNum.value;
|
||||
setter();
|
||||
location.href = './cards.html';
|
||||
} else {
|
||||
console.log("room number error");
|
||||
}
|
||||
});
|
||||
|
||||
var randomBtn = document.querySelector('#random');
|
||||
randomBtn.addEventListener('click',() => {
|
||||
roomID = "n"
|
||||
setter();
|
||||
location.href = './cards.html';
|
||||
});
|
||||
|
||||
// animation
|
||||
var steps = document.querySelector('.ts.steps');
|
||||
var step = document.querySelectorAll('.ts.steps .step');
|
||||
var container = document.querySelector('.ts.fluid.container');
|
||||
var title = document.querySelector('h1');
|
||||
var characterDialog = document.querySelector('#character');
|
||||
var roomDialog = document.querySelector('#room');
|
||||
|
||||
function displayCharacter() {
|
||||
btn.style.display = "none";
|
||||
steps.style.display = "flex";
|
||||
container.classList.remove('title');
|
||||
container.classList.remove('fluid');
|
||||
container.classList.add('dialog');
|
||||
characterDialog.style.display = "block";
|
||||
roomDialog.style.display = "none";
|
||||
characterDialog.classList.add('animated');
|
||||
characterDialog.classList.add('fadeIn');
|
||||
title.style.marginTop = "1em";
|
||||
step[0].classList.add('active');
|
||||
step[0].classList.remove('completed');
|
||||
step[1].classList.remove('active');
|
||||
}
|
||||
|
||||
function displayRoom() {
|
||||
step[0].classList.remove('active');
|
||||
step[0].classList.add('completed');
|
||||
step[1].classList.add('active');
|
||||
characterDialog.style.display = "none";
|
||||
roomDialog.style.display = "block";
|
||||
roomDialog.classList.add('animated');
|
||||
roomDialog.classList.add('fadeIn');
|
||||
}
|
4
web/stringFormat.js
Normal file
4
web/stringFormat.js
Normal file
@ -0,0 +1,4 @@
|
||||
/* https://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format */
|
||||
String.prototype.format = function(array) {
|
||||
return array.reduce((p,c) => p.replace('{}',c), this);
|
||||
};
|
BIN
web/won.png
Normal file
BIN
web/won.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
44
web/ws.js
Normal file
44
web/ws.js
Normal file
@ -0,0 +1,44 @@
|
||||
var socket; // create object
|
||||
|
||||
function init(host="wss://api.stoneapp.tech:8787"){
|
||||
socket = new WebSocket(host);
|
||||
console.log("Initializing connection...");
|
||||
|
||||
socket.onopen = function() {
|
||||
wsOnOpen(this.readyState);
|
||||
}
|
||||
|
||||
socket.onclose = function() {
|
||||
wsOnClose();
|
||||
}
|
||||
|
||||
socket.onmessage = function(msg) {
|
||||
var dataJson;
|
||||
try {
|
||||
dataJson = JSON.parse(msg.data);
|
||||
} catch(except) {
|
||||
console.log(msg.data);
|
||||
return null;
|
||||
}
|
||||
wsHandler(dataJson);
|
||||
}
|
||||
|
||||
socket.onerror = function(except) {
|
||||
wsOnError(except);
|
||||
}
|
||||
}
|
||||
|
||||
function quit() {
|
||||
if(socket != null){
|
||||
socket.close();
|
||||
socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
function send(msg) {
|
||||
try {
|
||||
socket.send(msg);
|
||||
} catch(ex) {
|
||||
console.log(ex);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user