Instant Wakamemo

わかめて上で動作するわかめてメモのようなものです。

  1. // ==UserScript==
  2. // @name Instant Wakamemo
  3. // @namespace http://mobajinro.s178.xrea.com/wakamemo/
  4. // @version 1.5.3
  5. // @description わかめて上で動作するわかめてメモのようなものです。
  6. // @author udop_
  7. // @match http://jinrou.dip.jp/~jinrou/cgi_jinro.cgi
  8. // @match http://61.215.66.131/~jinrou/cgi_jinro.cgi
  9. // @match http://www7a.biglobe.ne.jp/~kuri/cgi_jinro.cgi
  10. // @require https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
  11. // @run-at document-start
  12. // ==/UserScript==
  13.  
  14. ;(function ($) {
  15. "use strict"
  16.  
  17. if (document.body.bgColor == "#fee3aa") {
  18. //村画面でないときは出さない
  19. return false
  20. }
  21.  
  22. //**********************************************
  23. // 変数・クラスの宣言
  24. //**********************************************
  25.  
  26. Array.prototype.fillundef = function (def, lastindex) {
  27. lastindex = lastindex + 1 || this.length
  28. for (let i = 0; i < lastindex; i++) {
  29. if (this[i] === null || this[i] === undefined) {
  30. this[i] = JSON.parse(JSON.stringify(def))
  31. }
  32. }
  33. }
  34.  
  35. function range(a, b) {
  36. var ar = []
  37. a = a || playerInfo.length
  38. b = b || undefined
  39. if (!b) {
  40. for (let i = 0; i < a; i++) ar.push(i)
  41. } else {
  42. for (let i = a; i < b; i++) ar.push(i)
  43. }
  44. return ar
  45. }
  46.  
  47. var playerInfo,
  48. indexOfName,
  49. discussLog,
  50. deathLog,
  51. inputMode,
  52. votetimes,
  53. newestDay,
  54. today,
  55. setting,
  56. colorSetting
  57. var playertable = $("table").eq(1)
  58. var textareatable = $("table[cellspacing=0]").eq(-1)
  59. var discusstable = $("table[cellpadding=0]").not("table.CLSTABLE2").last()
  60. var infotable = $("table[cellspacing=0]").eq(0)
  61. var commandtable = $("table[cellspacing=0]").eq(-2)
  62. var textarea = $("textarea").eq(0)
  63. var body = $("body")
  64. var isdaytime = document.body.bgColor != "#000000"
  65.  
  66. var settingDefault = {
  67. rewrite_css: {
  68. value: "yes",
  69. option: { yes: "はい", no: "いいえ" },
  70. name: "見た目を変更する",
  71. },
  72. auto_import_log: {
  73. value: "onetime",
  74. option: { none: "しない", onetime: "投票時", alltime: "常時" },
  75. name: "自動ログ取得のタイミング",
  76. },
  77. alert_vote: {
  78. value: "onetime",
  79. name: "未投票時に警告する",
  80. option: { yes: "はい", no: "いいえ" },
  81. },
  82. send_support: {
  83. value: "ctrl",
  84. name: "支援キー+ENTERで送信",
  85. option: { none: "しない", ctrl: "CTRL", shift: "SHIFT" },
  86. },
  87. autoreload_interval: {
  88. value: "30",
  89. name: "自動更新(観戦時のみ)",
  90. option: { 10: "10秒", 20: "20秒", 30: "30秒", 60: "60分" },
  91. },
  92. theme_color: {
  93. value: "navy",
  94. name: "テーマカラー",
  95. option: {
  96. crimson: "紅",
  97. darkorange: "オレンジ",
  98. darkgreen: "緑",
  99. navy: "蒼",
  100. purple: "紫",
  101. sienna: "茶",
  102. },
  103. },
  104. layout: {
  105. value: "no",
  106. name: "表を横に並べる(横幅と相談)",
  107. option: { yes: "はい", no: "いいえ" },
  108. },
  109. grayregion: {
  110. value: "no",
  111. name: "人外と推理した占い師の結果は<br>完グレ判定に使用しない",
  112. option: { yes: "はい", no: "いいえ" },
  113. },
  114. coloringName: {
  115. value: "no",
  116. name: "役職で色分けする(試験運用)",
  117. option: { yes: "はい", no: "いいえ" },
  118. },
  119. }
  120.  
  121. var nameColor = {
  122. black: "なし",
  123. red: "赤",
  124. pink: "ピンク",
  125. blue: "青",
  126. green: "緑",
  127. purple: "紫",
  128. brown: "茶",
  129. gaming: "虹色",
  130. }
  131. var colorSettingDefault = {
  132. gray: {
  133. value: "black",
  134. name: "グレー",
  135. option: nameColor,
  136. },
  137. fortune: {
  138. value: "black",
  139. name: "占い",
  140. option: nameColor,
  141. },
  142. necro: {
  143. value: "black",
  144. name: "霊能",
  145. option: nameColor,
  146. },
  147. share: {
  148. value: "black",
  149. name: "共有",
  150. option: nameColor,
  151. },
  152. guard: {
  153. value: "black",
  154. name: "狩人",
  155. option: nameColor,
  156. },
  157. cat: {
  158. value: "black",
  159. name: "猫又",
  160. option: nameColor,
  161. },
  162. beast: {
  163. value: "black",
  164. name: "人外",
  165. option: nameColor,
  166. },
  167. }
  168. var data = {
  169. playerInfo: [],
  170. indexOfName: {},
  171. isAutoReload: false,
  172. discussLog: [],
  173. deathLog: { exec: [], bite: [] },
  174. isfilter: false,
  175. inputMode: "simple",
  176. villageno: 0,
  177. setting: settingDefault,
  178. votetimes: [],
  179. importlogday: 0,
  180. }
  181. var color = {
  182. crimson: { main: "crimson", sub: "#EC365A" },
  183. darkorange: { main: "darkorange", sub: "#FF9F32" },
  184. darkgreen: { main: "darkgreen", sub: "#009300" },
  185. navy: { main: "navy", sub: "#0000b2" },
  186. purple: { main: "purple", sub: "#B200B2" },
  187. sienna: { main: "sienna", sub: "#C66538" },
  188. }
  189.  
  190. class Tr {
  191. constructor(id, cl) {
  192. this.id = ""
  193. this.cl = ""
  194. if (id) this.id = id
  195. if (cl) this.cl = cl
  196. this.tds = []
  197. }
  198. add(val, cl) {
  199. var c = cl ? `class='${cl}'` : ""
  200. var td = `<td ${c}>${val}</td>`
  201. this.tds.push(td)
  202. }
  203. addhtml(html) {
  204. this.tds.push(html)
  205. }
  206. text() {
  207. var tr = "<tr"
  208. if (this.id) tr = tr + " id='" + this.id + "'"
  209. if (this.cl) tr = tr + " class='" + this.cl + "'"
  210. tr += ">"
  211. tr += this.tds.join("")
  212. tr += "</tr>"
  213. return tr
  214. }
  215. appendTo(jQueryObject) {
  216. jQueryObject.append(this.text())
  217. }
  218. }
  219.  
  220. var COLORLIST = {
  221. 0: "選択▼",
  222. 1: "明灰",
  223. 2: "暗灰",
  224. 3: "黄色",
  225. 4: "オレンジ",
  226. 5: "赤",
  227. 6: "水色",
  228. 7: "青",
  229. 8: "黄緑",
  230. 9: "紫",
  231. 10: "桃色",
  232. 11: "肌色",
  233. 12: "茶色",
  234. 13: "緑",
  235. 14: "若草色",
  236. 15: "真紅",
  237. 16: "薄茶色",
  238. 17: "藍色",
  239. 18: "蒼",
  240. 19: "ピンク",
  241. 20: "銀色",
  242. 21: "薄紫",
  243. 22: "象牙色",
  244. 23: "黒",
  245. }
  246.  
  247. //**********************************************
  248. // Session関係
  249. //**********************************************
  250.  
  251. function load() {
  252. if (localStorage.getItem("memodata")) {
  253. data = JSON.parse(localStorage.getItem("memodata"))
  254. }
  255.  
  256. playerInfo = data.playerInfo
  257. indexOfName = data.indexOfName
  258. discussLog = data.discussLog
  259. deathLog = data.deathLog
  260. votetimes = data.votetimes
  261.  
  262. var old_setting = data.setting
  263. data.setting = {}
  264. for (let k in settingDefault) {
  265. data.setting[k] = old_setting && k in old_setting ? old_setting[k] : settingDefault[k]
  266. }
  267. setting = data.setting
  268.  
  269. old_setting = data.colorSetting || colorSettingDefault
  270. data.colorSetting = {}
  271. for (let k in colorSettingDefault) {
  272. if (old_setting && k in old_setting) {
  273. data.colorSetting[k] = old_setting[k]
  274. } else {
  275. data.colorSetting[k] = colorSettingDefault[k]
  276. }
  277. }
  278. colorSetting = data.colorSetting
  279. save()
  280. }
  281.  
  282. function save() {
  283. localStorage.setItem("memodata", JSON.stringify(data))
  284. }
  285.  
  286. //**********************************************
  287. // import関係
  288. //**********************************************
  289.  
  290. function importLog() {
  291. updateplayerInfo()
  292. importDiscussLog()
  293. }
  294.  
  295. function updateplayerInfo() {
  296. //プレイヤー情報を取得
  297. //death…「能力がCOできなくなった日」を指す 3日目吊りなら4日目。3日目噛まれなら3日目
  298.  
  299. if (discussLog.length >= 2) {
  300. playertable.find("td:odd").each(function (i, v) {
  301. if (!$(v).html()) return false
  302. playerInfo[i].vital = $(v).html().includes("生存中") ? "alive" : "death"
  303. })
  304. } else {
  305. data.playerInfo = []
  306. playerInfo = data.playerInfo
  307. data.indexOfName = {}
  308. indexOfName = data.indexOfName
  309. playertable.find("td:odd").each(function (i, v) {
  310. var html = $(v).html()
  311. if (!html) return false
  312.  
  313. var name = html.split("<br>")[0]
  314. var vital = html.includes("生存中") ? "alive" : "death"
  315. playerInfo.push({
  316. no: i,
  317. name: name,
  318. vital: vital,
  319. job: "gray",
  320. reasoning: "gray",
  321. jobresult: [],
  322. vote: [],
  323. death: 99,
  324. })
  325. data.indexOfName[name] = i
  326. })
  327. }
  328. save()
  329. }
  330.  
  331. function importDiscussLog() {
  332. //ログ取り込み
  333. if (isdaytime) {
  334. discussLog[today] = []
  335. discusstable.find("tr").each(function (i, v) {
  336. if ($(v).children().length != 2) return true
  337. discussLog[today].push({
  338. name: $(v).children().eq(0).find("b").eq(0).html(),
  339. namehtml: $(v).children().eq(0).html(),
  340. content: $(v).children().eq(1).html(),
  341. })
  342. })
  343. }
  344.  
  345. //投票結果・死亡ログ
  346. var votelog = []
  347. discusstable.find("td[colspan='2']").each(function (i, v) {
  348. if (
  349. /(無残な姿で発見|死体で発見|村民協議の結果処刑|突然死|猫又の呪い)/.test($(v).text())
  350. ) {
  351. importDeath(v)
  352. }
  353. if (/\d{1,2}日目 投票結果。/.test($(v).text())) {
  354. votelog.unshift(v)
  355. }
  356. })
  357. if (votelog.length) importVote(votelog)
  358.  
  359. filterlog(99, newestDay)
  360. save()
  361. }
  362.  
  363. function importDeath(log) {
  364. //死体を記録
  365. var day = today
  366. var deathday = today
  367. var no = indexOfName[$(log).find("b").eq(0).text()]
  368. var text = $(log).text()
  369. var reason = ""
  370. if (/無残な姿で発見/.test(text)) {
  371. reason = "bite"
  372. } else if (/死体で発見/.test(text)) {
  373. reason = "note"
  374. } else if (/村民協議の結果|猫又の呪い/.test(text)) {
  375. reason = "exec"
  376. isdaytime ? day-- : deathday++
  377. } else if (/突然死/.test(text)) {
  378. reason = "sudden"
  379. deathday++
  380. }
  381. playerInfo[no].death = deathday
  382.  
  383. if (!deathLog[reason]) deathLog[reason] = []
  384. deathLog[reason].fillundef([], day)
  385.  
  386. if (!deathLog[reason][day].includes(no)) {
  387. deathLog[reason][day].push(no)
  388. }
  389. }
  390.  
  391. function importVote(logs) {
  392. //投票を取り込む
  393. var day = $(logs[0])
  394. .text()
  395. .match(/(\d{1,2})日目 投票結果。/)
  396. day = day[1] - 1
  397.  
  398. for (var player of playerInfo) {
  399. player.vote[day] = []
  400. player.vote.fillundef("-", logs.length)
  401. }
  402.  
  403. for (let times = 0; times < logs.length; times++) {
  404. $(logs[times])
  405. .find("tr")
  406. .each(function (i, vote) {
  407. var voter = indexOfName[$(vote).find("b").eq(0).text()]
  408. var target = $(vote).find("b").eq(1).text()
  409. playerInfo[voter].vote[day][times] = target
  410. })
  411. }
  412. votetimes[day] = logs.length
  413. votetimes.fillundef(0)
  414. }
  415.  
  416. //**********************************************
  417. // refresh関係
  418. //**********************************************
  419.  
  420. function refresh() {
  421. //再表示まとめて
  422. refreshDiscussLog()
  423. refreshPlayerInfoTable()
  424. refreshVoteTable()
  425. refreshSummary()
  426. }
  427.  
  428. function refreshPlayerInfoTable() {
  429. //プレイヤー情報更新 くっそ長い
  430.  
  431. //初期化
  432. playerInfoTable.empty()
  433.  
  434. if (!playerInfo.length) return false
  435.  
  436. var playersList = { 99: "" }
  437. for (let i of range()) {
  438. playersList[i] = playerInfo[i].name
  439. }
  440. var joblist = {
  441. gray: "",
  442. fortune: "占い",
  443. necro: "霊能",
  444. share: "共有",
  445. guard: "狩人",
  446. cat: "猫又",
  447. beast: "人外",
  448. }
  449. var reasoninglist = {
  450. gray: "",
  451. real: "真",
  452. fake: "偽",
  453. villager: "村人",
  454. madman: "狂人",
  455. wolf: "人狼",
  456. fox: "妖狐",
  457. }
  458. var resultlist = { notinput: "", white: "○", black: "●" }
  459.  
  460. //-------------------------名前列
  461. var namerow = new Tr("", "namerow")
  462. namerow.add("<a id='filterlink_99_99'>全ログ</a>")
  463. for (let player of playerInfo) {
  464. namerow.add(
  465. `<a id='filterlink_${player.no}_99'>${player.name}</a>`,
  466. `player_${player.no}`
  467. )
  468. }
  469. namerow.appendTo(playerInfoTable)
  470.  
  471. //-------------------------発言数列
  472. for (var day = 1; day <= newestDay; day++) {
  473. var row = new Tr("", "talknumrow")
  474. row.add(`<a id=filterlink_99_${day}>${day + 1}日目</a>`)
  475. for (let player of playerInfo) {
  476. var talknum = $("#log_day" + day).find("tr.talk_player" + player.no).length
  477. if (talknum === 0) talknum = ""
  478. row.add(
  479. `<a id=filterlink_${player.no}_${day}>${talknum}</a>`,
  480. "player_" + player.no
  481. )
  482. }
  483. row.appendTo(playerInfoTable)
  484. }
  485.  
  486. //-------------------------CO列
  487. var jobrow = new Tr("", "jobrow")
  488. jobrow.add("CO")
  489. for (let player of playerInfo) {
  490. let select = createSelectBox(joblist, player.job, {
  491. id: `player_${player.no}_job`,
  492. class: "jobselect",
  493. })
  494. jobrow.add(select, "player_" + player.no)
  495. }
  496. jobrow.appendTo(playerInfoTable)
  497.  
  498. //-------------------------推理列
  499. jobrow = new Tr("", "jobrow")
  500. jobrow.add("推理")
  501. for (let player of playerInfo) {
  502. let select = createSelectBox(reasoninglist, player.reasoning, {
  503. id: `player_${player.no}_reasoning`,
  504. class: "reasoningselect",
  505. })
  506. jobrow.add(select, "player_" + player.no)
  507. }
  508. playerInfoTable.append(jobrow.text())
  509.  
  510. //-------------------------役職結果列
  511. for (day = 1; day <= newestDay; day++) {
  512. var resultrow = new Tr("result_" + day, "resultrow")
  513. resultrow.add(`占霊結果 ${day + 1}日目`)
  514.  
  515. for (let player of playerInfo) {
  516. if (
  517. (player.job == "fortune" && day < player.death) ||
  518. (player.job == "necro" && day < player.death && day > 1)
  519. ) {
  520. //占い師、霊能者で、結果があるなら
  521. let select1 = createSelectBox(playersList, 99, {
  522. id: `target_${player.no}_${day}`,
  523. class: "jobtarget",
  524. })
  525. let select2 = createSelectBox(resultlist, "notinput", {
  526. id: `judge_${player.no}_${day}`,
  527. class: "jobjudge",
  528. })
  529. resultrow.add(select1 + select2, "player_" + player.no)
  530. } else {
  531. resultrow.add("", "player_" + player.no)
  532. }
  533. }
  534. playerInfoTable.append(resultrow.text())
  535. }
  536. refreshJobResult()
  537. switchAliveFilter()
  538. switchInputMode()
  539. coloring()
  540.  
  541. //絞込機能つける
  542. $("#playerInfoTable a").on("click", function (e) {
  543. var id = $(this).attr("id").split("_")
  544. filterlog(id[1], id[2])
  545. })
  546.  
  547. //変更は逐一反映
  548. $("select.jobselect").on("change", function () {
  549. var no = $(this).attr("id").split("_")[1] - 0
  550. playerInfo[no].job = $(this).val()
  551.  
  552. refreshPlayerInfoTable()
  553. refreshJobInitial()
  554. refreshSummary()
  555. if (setting.coloringName.value == "yes") setNameColor()
  556. save()
  557. })
  558.  
  559. $("select.reasoningselect").on("change", function () {
  560. var no = $(this).attr("id").split("_")[1] - 0
  561. playerInfo[no].reasoning = $(this).val()
  562.  
  563. refreshJobInitial()
  564. coloring()
  565. save()
  566. })
  567.  
  568. $("select.jobtarget").on("change", function (e) {
  569. var id, no, day
  570. ;[id, no, day] = $(this).attr("id").split("_")
  571.  
  572. playerInfo[no].jobresult.fillundef({ target: 99, judge: "notinput" }, +day)
  573. playerInfo[no].jobresult[day].target = $(this).val() - 0
  574.  
  575. refreshSummary()
  576. coloring()
  577. save()
  578. })
  579.  
  580. $("select.jobjudge").on("change", function (e) {
  581. var id, no, day
  582. ;[id, no, day] = $(this).attr("id").split("_")
  583.  
  584. playerInfo[no].jobresult.fillundef({ target: 99, judge: "notinput" }, +day)
  585. playerInfo[no].jobresult[day].judge = $(this).val()
  586. refreshSummary()
  587. coloring()
  588. save()
  589. })
  590. }
  591.  
  592. function refreshJobResult() {
  593. var fortunes = playerInfo.filter((p) => {
  594. return p.job == "fortune"
  595. })
  596. for (let fortune of fortunes) {
  597. for (let day = 1; day < Math.min(fortune.death, newestDay + 1); day++) {
  598. if (fortune.jobresult[day]) {
  599. //既に結果が入力されているとき
  600. $("#target_" + fortune.no + "_" + day).val(fortune.jobresult[day].target)
  601. $("#judge_" + fortune.no + "_" + day).val(fortune.jobresult[day].judge)
  602. }
  603. }
  604. }
  605.  
  606. var necros = playerInfo.filter((p) => {
  607. return p.job == "necro"
  608. })
  609. for (let necro of necros) {
  610. for (let day = 2; day < Math.min(necro.death, newestDay + 1); day++) {
  611. if (necro.jobresult[day]) {
  612. //既に結果が入力されているとき
  613. $("#target_" + necro.no + "_" + day).val(necro.jobresult[day].target)
  614. $("#judge_" + necro.no + "_" + day).val(necro.jobresult[day].judge)
  615. } else if (deathLog.exec[day - 1]) {
  616. $("#target_" + necro.no + "_" + day).val(deathLog.exec[day - 1])
  617. }
  618. }
  619. }
  620. }
  621.  
  622. function refreshDiscussLog() {
  623. discussLogTable.empty()
  624. if (!discussLog.length) return false
  625.  
  626. discussLog.forEach(function (logs, day) {
  627. if (!logs) return
  628.  
  629. var tbody = $("<tbody></tbody>", { id: "log_day" + day })
  630. var trs = `<tr class="systemlog"><td colspan="2">${day + 1}日目</td></tr>`
  631.  
  632. for (var log of logs) {
  633. var cl = log.name in indexOfName ? "talk_player" + indexOfName[log.name] : ""
  634. trs += `<tr class="${cl}"><td>${log.namehtml}<span class='jobinitial'></span></td><td>${log.content}</td></tr>`
  635. }
  636. tbody.append(trs).prependTo(discussLogTable)
  637. })
  638. refreshJobInitial()
  639. }
  640.  
  641. function refreshJobInitial() {
  642. var jobinitial = {
  643. fortune: "占",
  644. necro: "霊",
  645. share: "共",
  646. cat: "猫",
  647. guard: "狩",
  648. wolf: "狼",
  649. madman: "狂",
  650. fox: "狐",
  651. villager: "村",
  652. real: "真",
  653. fake: "偽",
  654. beast: "外",
  655. gray: "",
  656. }
  657. for (var player of playerInfo) {
  658. var job = jobinitial[player.reasoning] + jobinitial[player.job]
  659. $("tr.talk_player" + player.no + " span").html(job)
  660. }
  661. }
  662.  
  663. function refreshVoteTable() {
  664. //投票テーブルリライト
  665. voteTable.empty()
  666.  
  667. var tr = new Tr()
  668. tr.add("プレイヤー")
  669. for (var day = 1; day <= newestDay; day++) {
  670. let colspan = votetimes[day] || 1
  671. tr.addhtml(`<td colspan="${colspan}">${day + 1}日目</td>`)
  672. }
  673. voteTable.append(tr.text())
  674.  
  675. for (var player of playerInfo) {
  676. tr = new Tr()
  677. tr.add(player.name)
  678. for (day = 1; day <= newestDay; day++) {
  679. let times = votetimes[day] || 1
  680. for (let i = 0; i < times; i++) {
  681. var text = player.vote[day] && player.vote[day][i] ? player.vote[day][i] : "-"
  682. tr.add(text)
  683. }
  684. }
  685. voteTable.append(tr.text())
  686. }
  687. }
  688.  
  689. function refreshSummary() {
  690. var color = { notinput: "?", white: "○", black: "●" }
  691. var reasons = ["bite", "note", "exec", "sudden"]
  692. var reasonflavor = { bite: "無残", note: "デスノ", exec: "処刑", sudden: "突然死" }
  693.  
  694. summaryTable.empty()
  695.  
  696. var tr = new Tr()
  697. tr.addhtml("<td colspan='2'></td>")
  698. for (var day = 1; day <= newestDay; day++) {
  699. tr.add("" + (day + 1) + "日目")
  700. }
  701. tr.appendTo(summaryTable)
  702.  
  703. var fn = playerInfo.filter((player) => {
  704. return player.job == "fortune"
  705. })
  706.  
  707. for (let i = 0; i < fn.length; i++) {
  708. let player = fn[i]
  709. tr = new Tr()
  710. if (i == 0) tr.addhtml(`<td rowspan=${fn.length}>占い師</td>`)
  711. tr.add(player.name)
  712.  
  713. for (day = 1; day <= newestDay; day++) {
  714. let name = "",
  715. judge = ""
  716. if (player.jobresult[day] && player.jobresult[day].target != 99) {
  717. name = playerInfo[player.jobresult[day].target].name
  718. judge = color[player.jobresult[day].judge]
  719. }
  720. tr.add(name + judge)
  721. }
  722. tr.appendTo(summaryTable)
  723. }
  724.  
  725. fn = playerInfo.filter((player) => {
  726. return player.job == "necro"
  727. })
  728.  
  729. for (let i = 0; i < fn.length; i++) {
  730. let player = fn[i]
  731. tr = new Tr()
  732. if (i == 0) tr.addhtml(`<td rowspan=${fn.length}>霊能者</td>`)
  733. tr.add(player.name)
  734. for (let day = 1; day <= newestDay; day++) {
  735. let name = "",
  736. judge = ""
  737. if (player.jobresult[day] && player.jobresult[day].target != 99) {
  738. name = playerInfo[player.jobresult[day].target].name
  739. judge = color[player.jobresult[day].judge]
  740. }
  741. tr.add(name + judge)
  742. }
  743. tr.appendTo(summaryTable)
  744. }
  745.  
  746. for (var reason of reasons) {
  747. if (!deathLog[reason]) continue
  748.  
  749. tr = new Tr()
  750. if (reason == "bite") tr.addhtml("<td rowspan='4'>死亡ログ</td>")
  751. tr.add(reasonflavor[reason])
  752.  
  753. for (day = 1; day <= newestDay; day++) {
  754. var text = "-"
  755. if (deathLog[reason][day]) {
  756. text = deathLog[reason][day].map((x) => playerInfo[x].name).join("<br>")
  757. }
  758. tr.add(text)
  759. }
  760. tr.appendTo(summaryTable)
  761. }
  762. }
  763.  
  764. //**********************************************
  765. // 表示
  766. //**********************************************
  767.  
  768. var switchDispArea = function (_this) {
  769. //メモのログ/投票表示切り替え
  770. $("div.tab").removeClass("active")
  771. $(_this).addClass("active")
  772.  
  773. $("#memoBody > div").hide()
  774. var mode = $(_this).data("value")
  775. $(`#${mode}Area`).show()
  776. }
  777.  
  778. function switchAliveFilter(_this) {
  779. if (_this) {
  780. data.isfilter = $(_this).data("value") == "on"
  781. save()
  782. }
  783. $("div.select.filter").removeClass("active")
  784. data.isfilter
  785. ? $("#showAliveButton").addClass("active")
  786. : $("#showAllButton").addClass("active")
  787. for (var player of playerInfo) {
  788. if (!data.isfilter || player.vital == "alive" || player.job != "gray") {
  789. $("td.player_" + player.no).show()
  790. } else {
  791. $("td.player_" + player.no).hide()
  792. }
  793. }
  794. }
  795.  
  796. function switchInputMode(_this) {
  797. if (_this) {
  798. data.inputMode = $(_this).data("value")
  799. save()
  800. }
  801. $("div.select.inputmode").removeClass("active")
  802. $(`#input${data.inputMode}Button`).addClass("active")
  803. for (var day = 1; day <= newestDay; day++) {
  804. if (data.inputMode == "full" || (data.inputMode == "simple" && day == newestDay)) {
  805. $("#result_" + day).show()
  806. } else {
  807. $("#result_" + day).hide()
  808. }
  809. }
  810. }
  811.  
  812. function filterlog(player, day) {
  813. if (player < 99) {
  814. $("#discussLogTable tr").hide()
  815. $("tr.systemlog").show()
  816. $("tr.talk_player" + player).show()
  817. } else {
  818. $("#discussLogTable tr").show()
  819. }
  820.  
  821. if (day < 99) {
  822. $("#discussLogTable tbody").hide()
  823. $("#log_day" + day).show()
  824. } else {
  825. $("#discussLogTable tbody").show()
  826. }
  827. }
  828.  
  829. function coloring() {
  830. var notgray = range().filter((i) => playerInfo[i].job != "gray")
  831.  
  832. var fortunes = playerInfo.filter((player) => player.job == "fortune")
  833. if (setting.grayregion.value == "yes") {
  834. fortunes = fortunes.filter((fortune) => {
  835. return fortune.reasoning == "gray" || fortune.reasoning == "real"
  836. })
  837. }
  838. fortunes.forEach(function (player) {
  839. notgray = notgray.concat(player.jobresult.map((p) => p.target))
  840. })
  841.  
  842. var graylist = range().filter((no) => {
  843. return !notgray.includes(no)
  844. })
  845.  
  846. $("tr.namerow td").removeClass("death").removeClass("gray")
  847. for (var player of playerInfo) {
  848. if (player.vital == "death") {
  849. $("tr.namerow .player_" + player.no).addClass("death")
  850. } else if (graylist.includes(player.no)) {
  851. $("tr.namerow .player_" + player.no).addClass("gray")
  852. }
  853. }
  854. }
  855.  
  856. function reset() {
  857. data = {
  858. playerInfo: [],
  859. indexOfName: {},
  860. isAutoReload: false,
  861. importlogday: 0,
  862. discussLog: [],
  863. deathLog: { exec: [], bite: [] },
  864. isfilter: false,
  865. inputMode: "simple",
  866. villageno: getVillageno(),
  867. setting: data.setting,
  868. votetimes: [],
  869. }
  870. playerInfo = data.playerInfo
  871. indexOfName = data.indexOfName
  872. discussLog = data.discussLog
  873. deathLog = data.deathLog
  874. setting = data.setting
  875. votetimes = data.votetimes
  876. save()
  877. }
  878.  
  879. //**********************************************
  880. // 乱数表
  881. //**********************************************
  882.  
  883. function rnd(n, digit) {
  884. //0~n-1の整数乱数 digitを指定するとゼロパディング
  885. digit = digit || false
  886. var r = Math.floor(Math.random() * n)
  887. if (digit) r = padding(r, digit)
  888. return r
  889. }
  890.  
  891. function padding(num, digit) {
  892. //ゼロパディング
  893. return ("0000000000" + num).slice(-digit)
  894. }
  895.  
  896. function makernd() {
  897. //四桁乱数
  898. return rnd(10000, 4)
  899. }
  900.  
  901. function makematrix(num) {
  902. //乱数表
  903. var l = []
  904. var mat = ""
  905. for (var i = 0; i < num; i++) {
  906. l[i] = padding(i + 1, 2)
  907. }
  908. for (i = 0; i < num; i++) {
  909. var r = rnd(num - i)
  910. mat += l[r]
  911. mat += i % 5 == 4 ? "\n" : " / "
  912. for (var j = r; j < num - 1; j++) {
  913. l[j] = l[j + 1]
  914. }
  915. }
  916. return mat
  917. }
  918.  
  919. function makerndjob(num) {
  920. //役職対応
  921. var jobs = ["村 人", "占い師", "霊能者", "狩 人", "共有者", "狂 人", "背徳者"]
  922. var cir = ["①", "②", "③", "④", "⑤", "⑥", "⑦"]
  923. var result = ""
  924. var isimo = num == 15 || num == 19
  925. var n = isimo ? 7 : 6
  926. var i, r
  927. if (isimo) {
  928. result += cir[rnd(n)] + "\n\n"
  929. }
  930. var l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  931. for (i = 0; i < n; i++) {
  932. r = rnd(10 - i)
  933. result = result + jobs[i] + ":" + l[r] + rnd(100, 2) + "\n"
  934. for (var j = r; j <= num - 1; j++) {
  935. l[j] = l[j + 1]
  936. }
  937. }
  938. return result
  939. }
  940.  
  941. //**********************************************
  942. // その他小物
  943. //**********************************************
  944.  
  945. function getToday() {
  946. //表示されている日付チェック
  947. var day = /<font size="\+2">(\d{1,2})/.exec(body.html())
  948. today = day ? day[1] - 1 : 0
  949. newestDay = Math.max(today, discussLog.length - 1)
  950. }
  951.  
  952. function getVillageno() {
  953. var vno = $("title").text().slice(0, 6) - 0
  954. return vno
  955. }
  956.  
  957. function createSelectBox(option, selected, attr) {
  958. //optionを持つselectを作る。str。optionは{value: innerHTML}の形式で
  959. let attrtext = ""
  960. if (attr) {
  961. for (let k in attr) {
  962. attrtext = attrtext + ` ${k}="${attr[k]}"`
  963. }
  964. }
  965. var s = `<select${attrtext}>`
  966. for (var i in option) {
  967. let issl = i == selected ? "selected" : ""
  968. s += `<option value="${i}" ${issl}>${option[i]}</option>`
  969. }
  970. s += "</select>"
  971. return s
  972. }
  973.  
  974. function editSpeakField(text) {
  975. //発言欄をtextにする
  976. textarea.val(text)
  977. memoContainer.hide()
  978. }
  979.  
  980. function popupMessage(text) {
  981. //メッセージ
  982. messageArea.text(text).show()
  983. setTimeout(function () {
  984. messageArea.hide()
  985. }, 1500)
  986. }
  987.  
  988. //**********************************************
  989. // 便利設定
  990. //**********************************************
  991. var left
  992. function setAlertVote() {
  993. //未投票アラート
  994. if ($("font[size=6]").size()) {
  995. warningArea.show()
  996. var cmbplayer = $("select[name=CMBPLAYER]").clone()
  997. var votebutton = $("<input />", {
  998. type: "button",
  999. value: "投票",
  1000. on: {
  1001. click: function () {
  1002. $("select").eq(0).val("VOTE")
  1003. document.forms[0].submit()
  1004. },
  1005. },
  1006. })
  1007. left = counts
  1008. warningArea.html("未投票です! あと<span id='left'></span>秒")
  1009. warningArea.append(cmbplayer)
  1010. warningArea.append(votebutton)
  1011. cmbplayer.on("change", function () {
  1012. $("select[name=CMBPLAYER]").val($(this).val())
  1013. })
  1014. $("#left").html(left)
  1015. setInterval(function () {
  1016. left--
  1017. $("#left").html(left)
  1018. }, 1000)
  1019. }
  1020. }
  1021.  
  1022. function receiveKeyResponse() {
  1023. //キー入力を受け付けるかどうか
  1024. $(window).on("keydown", function (e) {
  1025. if (setting.send_support.value == "ctrl" && e.ctrlKey && e.keyCode == 13) {
  1026. document.forms[0].submit()
  1027. } else if (setting.send_support.value == "shift" && e.shiftKey && e.keyCode == 13) {
  1028. document.forms[0].submit()
  1029. }
  1030. })
  1031. }
  1032.  
  1033. function dispSuggest() {
  1034. var colorselect = createSelectBox(COLORLIST, 0, { id: "colorlist" })
  1035. var coloredit = `<td class="coloredit">アイコン色:</td><td class="coloredit">${colorselect}</td>`
  1036. var iconsupport =
  1037. "<td class='iconsupport'><input type='button' id='pasteurl' value='/../../imgbbs/img/'></td>"
  1038.  
  1039. commandtable.find("td").eq(1).after(coloredit).after(iconsupport)
  1040. commandtable.find("td").eq(-2).addClass("cmbplayer")
  1041. commandtable.find("td").eq(-1).addClass("cmbplayer")
  1042.  
  1043. $("#colorlist").on("change", function () {
  1044. editSpeakField($(this).val())
  1045. })
  1046. $("#pasteurl").on("click", function () {
  1047. editSpeakField("/../../imgbbs/img/")
  1048. })
  1049. $("select")
  1050. .eq(0)
  1051. .on("change", function () {
  1052. $("td.coloredit").hide()
  1053. $("td.iconsupport").hide()
  1054. $("td.cmbplayer").hide()
  1055. if ($(this).val() == "ICONCHG") {
  1056. $("td.coloredit").show()
  1057. } else if ($(this).val() == "BCONCHG") {
  1058. $("td.iconsupport").show()
  1059. } else {
  1060. $("td.cmbplayer").show()
  1061. }
  1062. })
  1063. }
  1064.  
  1065. function highlightDeathnote() {
  1066. var td = infotable.find("td:last")
  1067. if (/アナタの家の前に/.test(td.html())) {
  1068. td.css("color", "red")
  1069. }
  1070. }
  1071.  
  1072. function setAutoImportLog() {
  1073. if (!data.importlogday) data.importlogday = 0
  1074. if (setting.auto_import_log.value == "alltime") {
  1075. importLog()
  1076. } else if (setting.auto_import_log.value == "onetime") {
  1077. if (today > data.importlogday && /<font size="\+2">投票/.test(body.html())) {
  1078. data.importlogday = today
  1079. importLog()
  1080. save()
  1081. popupMessage("ログを取り込みました。")
  1082. }
  1083. }
  1084. }
  1085.  
  1086. var autoReloadFlg
  1087.  
  1088. function setAutoReload() {
  1089. autoReloadFlg = setTimeout(function () {
  1090. textarea.val("")
  1091. document.forms[0].submit()
  1092. }, setting.autoreload_interval.value * 1000)
  1093. }
  1094.  
  1095. function castASpellOnMe() {
  1096. var q = $("#caspequery").val()
  1097. var num = $("#caspenum").val()
  1098. if (num > 10) num = 10
  1099. $.post(
  1100. "http://mobajinro.s178.xrea.com/caspe/getWaffle.php",
  1101. {
  1102. query: q,
  1103. num: num,
  1104. },
  1105. function (data) {
  1106. var txt = data.replace(/\n+/g, "<br>")
  1107. var nos = txt.match(/\d{4}/g)
  1108. if (nos) {
  1109. for (var no of nos) {
  1110. var src = no
  1111. if (no - 0 > 4674) src = "/../../imgbbs/img/" + no
  1112. txt = txt.replace(
  1113. no,
  1114. `<img data-no='${no}' src='http://jinrou.dip.jp/~jinrou/img/alive_${src}.gif'>`
  1115. )
  1116. }
  1117. }
  1118. $("#casperesult").html(txt)
  1119. $("#casperesult img").on("click", function () {
  1120. $("#iconno").val($(this).data("no"))
  1121. $("#casperesult img").removeClass("iconselected")
  1122. $(this).addClass("iconselected")
  1123. })
  1124. }
  1125. )
  1126. }
  1127.  
  1128. function setClipboard(text, disc) {
  1129. //クリップボードにコピー 発言欄初期化する注意
  1130. textarea.val(text).select()
  1131. document.execCommand("copy")
  1132. textarea.val("")
  1133. }
  1134.  
  1135. function setNameColor() {
  1136. if (setting.coloringName.value != "yes") return false
  1137. $("b").each((i, e) => {
  1138. let name = $(e).text()
  1139. if (name in indexOfName) {
  1140. let i = indexOfName[name]
  1141. let job = playerInfo[i].job
  1142. $(e).removeClass().addClass(colorSetting[job].value)
  1143. }
  1144. })
  1145. }
  1146.  
  1147. //**********************************************
  1148. // 個人設定の読み込み
  1149. //**********************************************
  1150.  
  1151. load()
  1152.  
  1153. //**********************************************
  1154. // cssの追加と書き換え
  1155. //**********************************************
  1156. var style = []
  1157.  
  1158. //見た目変更
  1159. if (setting.rewrite_css.value == "yes") {
  1160. style = [
  1161. ".CLSTABLE tr td:nth-of-type(even) {font-size: 12px;line-height: 110%;padding: 2px;}",
  1162. ".CLSTABLE tr td:nth-of-type(odd) {font-size: 0px;padding: 2px;}",
  1163. 'body[bgcolor="#000000"] font[color="#6666aa"] {color: #ccccff;}',
  1164. 'font[size="-1"] {font-size: 9pt;}',
  1165. "img {padding: 0;}",
  1166. "input,select {font-size: 9pt;}",
  1167. "table {font-size: 13px;}",
  1168. 'textarea {font-family: "Meiryo";font-size: 11px;min-height: 100px;}',
  1169. 'table[cellpadding="0"] tr td:nth-of-type(2){word-break:break-all;}',
  1170. ]
  1171. }
  1172.  
  1173. //追加分
  1174. style = style.concat([
  1175. `:root{--theme-color:${color[setting.theme_color.value].main}; --sub-color:${
  1176. color[setting.theme_color.value].sub
  1177. };}`,
  1178. "*{box-sizing:border-box;}",
  1179. "body{margin:0;}",
  1180. "form{margin:8px;}",
  1181. "#memoContainer{display:none; width:100%; height:100%; position:fixed; top:0px; left:0px; background-color:rgba(180,180,180,0.8); padding:15px; overflow:auto;}",
  1182. "#floatButtonArea{position:fixed; right:15px; top:15px;}",
  1183. "#floatButtonArea > div{margin:0px 2px; display:inline-block; vertical-align: top; width:110px; box-shadow: 0 3px 5px rgba(0, 0, 0, 0.4);}",
  1184. "#messageArea{width:400px; height:80px; position:fixed; left:50%; transform: translate(-50%, 0); top:15px; display:none;}",
  1185. "#messageArea{text-align:center;font-size:14px; color:black;vertical-align:middle;padding-top:5px;}",
  1186. "#warningArea{width:100%; height:40px; padding:5px; position:fixed; bottom:0; display:none; background-color:darkorange; text-align:center; font-size:16px; color:white; font-weight:bold;}",
  1187. "#left{font-size:30px;}",
  1188. "#warningArea select, #warningArea input{font-size:11pt; vertical-align:middle;}",
  1189.  
  1190. "#memoMenu{width:100%; margin: 0 auto; font-size:10px;}",
  1191. "#memoMenu input, #memoMenu select, #buttonArea input{font-size:11px;}",
  1192. "#memoTab{margin-top:15px;}",
  1193. "#memoBody{width:100%; height:calc(100% - 63px); margin: 0 auto; }",
  1194.  
  1195. "#logArea,#voteArea{width:100%; height:100%; overflow:auto; margin: 0 auto; background-color:white; padding:10px; border-radius:0px 8px 8px 8px ;}",
  1196. "#voteArea{display:none;}",
  1197.  
  1198. "#discussLogTable{border-collapse:collapse;}",
  1199. "#discussLogTable td{text-align:left;vertical-align:top; color:black; word-break:break-all; font-size:9pt; line-height:140%; padding:2px;}",
  1200. "#discussLogTable font{font-size:9pt;}",
  1201. "#discussLogTable tr td:first-of-type{min-width:150px;}",
  1202. "#discussLogTable tr.systemlog td{font-weight:bold;background-color:var(--theme-color) !important; color:white; text-align:center;}",
  1203. "#playerInfoTable a{text-decoration:underline; color:blue; cursor:pointer;}",
  1204. "#playerInfoTable tr.namerow td.death {background-color:pink;}",
  1205. "#playerInfoTable tr.namerow td.gray {background-color:#e3e3e3;}",
  1206. "#voteTable, #summaryTable{font-size:11px; border-collapse:collapse; margin-bottom:10px;color:black;}",
  1207. "#voteTable td, #summaryTable td{border:1px solid #666; padding:2px; }",
  1208. "#toolArea_hid {display:none;}",
  1209. "#setting, #colorSetting{font-size:13px; position:fixed; right:10px; bottom:10px; display:none; width:400px; height:300px; background-color:white;}",
  1210. "#setting input[type=number], #setting input[type=text]{width:60px;}",
  1211. ".coloredit, .iconsupport{display:none;}",
  1212. ".voiceloud {padding:0px 5px;}",
  1213. ".voiceloud div:not(:first-of-type){margin-top:5px;}",
  1214. ".voice {width:30px;height:30px;font-size:16px;border:1px solid black; border-radius:2px;background-color:white;line-height:28px;text-align:center;color:black; cursor:pointer;}",
  1215. ".voice.voice_selected{border:3px solid red; line-height:24px;}",
  1216. "#caspe{display:none; position:fixed; right:10px; bottom:10px; width:400px; height:300px; solid #333; overflow:auto; font-size:9pt;}",
  1217. "#caspe input[type=text]{width:100px;}",
  1218. "#caspe input[type=number]{width:50px}",
  1219. "#caspe, #setting,#colorSetting, #messageArea{box-shadow: 0 3px 5px rgba(0, 0, 0, 0.4); border-top:16px solid var(--theme-color); background-color:#efefef; padding:10px;}",
  1220. "#floatButtonArea a, .button{width:110px; color:white; background-color:var(--theme-color); cursor:pointer; display:inline-block; font-size:12px; font-weight:bold; line-height:24px; text-align:center;}",
  1221. "div.button{margin:0px 2px; box-shadow: 0 3px 5px rgba(0, 0, 0, 0.4); padding:0px 3px;}",
  1222. ".tab{width:150px; color:white; background-color:var(--theme-color);cursor:pointer; display:inline-block; font-size:12px; line-height:24px; text-align:center; border-radius:8px 8px 0 0;}",
  1223. ".tab.active{color:var(--theme-color); background-color:white;font-weight:bold;}",
  1224. "#floatButtonArea a:hover, div.button:hover{background-color:var(--sub-color);}",
  1225. ".closebutton{position:absolute; right:5px; top:5px;}",
  1226. "#caspe img{padding:2px;}",
  1227. "#caspe img.iconselected{border:2px solid var(--theme-color); padding:0px;}",
  1228. ".jobinitial{user-select:none; color:var(--theme-color); font-weight:bold; font-size:80%;}",
  1229. ".jobinitial:not(:empty):before{content:'[';}",
  1230. ".jobinitial:not(:empty):after{content:']';}",
  1231. ".black{} .pink{color:deeppink;} .red{color:red;} .green{color:green;}",
  1232. ".purple{color:purple;} .brown{color:brown;} .blue{color:blue;}",
  1233. ".gaming{background:linear-gradient(to right, #f33,#ff3,#3f3,#3ff,#33f,#f3f,#f33) ;-webkit-background-clip: text; -webkit-text-fill-color:transparent;}",
  1234. ])
  1235. if (setting.layout.value == "yes") {
  1236. style = style.concat([
  1237. "#logArea{display: flex; flex-direction:column; flex-wrap:wrap;}",
  1238. "#playerInfoArea{height:calc(100% - 50px); overflow:auto hidden; width:50%; padding:5px;}",
  1239. "#playerInfoArea select{font-size:8.5pt;}",
  1240. "#buttonArea{height:50px;font-size:12px; padding:5px;}",
  1241. "#buttonArea > div{ margin-bottom:5px;}",
  1242. "#discussLogArea{width:50%; overflow:auto; padding:5px;}",
  1243. ".select{color:var(--theme-color); border-width:2px 2px 2px 0px ;border-color:var(--theme-color); border-style:solid; background-color:white; cursor:pointer; text-align:center; display:inline-block;width:100px;}",
  1244. ".select.active{color:white;background-color:var(--theme-color); font-weight:bold;}",
  1245. "#buttonArea > div > div.select:first-of-type{margin-left:5px; border-left:2px solid var(--theme-color);}",
  1246. "#buttonArea > div > div.select:lastof-type{margin-right:5px;}",
  1247. "#playerInfoTable{background-color:white; text-align:center; font-size:8pt; color:black; width:100%; margin:0px 2px 2px 0px;}",
  1248. "#playerInfoTable tbody{display:flex; flex-direction:row;border-spacing:0;}",
  1249. "#playerInfoTable tr{display:flex; flex-direction:column; flex:0 0 40px;}",
  1250. "#playerInfoTable tr.namerow{display:flex; flex-direction:column; flex:0 0 80px; position:sticky; left:0;}",
  1251. "#playerInfoTable tr.namerow td{background-color:white;}",
  1252. "#playerInfoTable tr.resultrow{display:flex; flex-direction:column; flex:0 0 140px;}",
  1253. "#playerInfoTable td{border-right:#666 solid 1px;border-bottom:#666 solid 1px;padding:1px; display:block; width:auto; height:1.8em; }",
  1254. "#playerInfoTable tr:first-of-type td{border-left:#666 solid 1px;}",
  1255. "#playerInfoTable tr td:first-of-type{border-top:#666 solid 1px;}",
  1256. ])
  1257. } else {
  1258. style = style.concat([
  1259. "#buttonArea{padding:10px;line-height:24px;font-size:9pt;}",
  1260. "#buttonArea > div{display:inline-block;}",
  1261. "#playerInfoArea{overflow:auto;}",
  1262. ".select{width:100px; color:var(--theme-color); border-width:2px 2px 2px 0px ;border-color:var(--theme-color); border-style:solid; background-color:white; cursor:pointer; display:inline-block; font-size:12px; line-height:20px; text-align:center;}",
  1263. ".select.active{color:white;background-color:var(--theme-color); font-weight:bold;}",
  1264. "#buttonArea > div > div.select:first-of-type{margin-left:5px; border-left:2px solid var(--theme-color);}",
  1265. "#buttonArea > div > div.select:last-of-type{margin-right:5px;}",
  1266. "#playerInfoTable {background-color:white;text-align:center; font-size:8pt;border-collapse:collapse; color:black; margin:0 auto;}",
  1267. "#playerInfoTable td{border:#666 solid 1px; padding:1px; }",
  1268. "#playerInfoTable tr.namerow{height:35px;}",
  1269. "#playerInfoTable tr td:first-child{min-width:50px;}",
  1270. ])
  1271. }
  1272. $("<style></style>").html(style.join("\n")).appendTo($("head"))
  1273.  
  1274. //**********************************************
  1275. // ツール用のもろもろを追加
  1276. //**********************************************
  1277.  
  1278. //大枠
  1279. var memoContainer = $("<div></div>", { id: "memoContainer" }).appendTo(body)
  1280. var messageArea = $("<div></div>", { id: "messageArea" }).appendTo(body)
  1281. var warningArea = $("<div></div>", { id: "warningArea" }).appendTo(body)
  1282. var floatButtonArea = $("<div></div>", { id: "floatButtonArea" }).appendTo(body)
  1283. var settingArea = $("<div></div>", { id: "setting" }).appendTo(body)
  1284. var colorSettingArea = $("<div></div>", { id: "colorSetting" }).appendTo(body)
  1285. var caspe = $("<div></div>", { id: "caspe" }).appendTo(body)
  1286.  
  1287. //ブロック
  1288. var memoMenu = $("<div></div>", { id: "memoMenu" }).appendTo(memoContainer)
  1289. var memoTab = $("<div></div>", { id: "memoTab" }).appendTo(memoContainer)
  1290. var memoBody = $("<div></div>", { id: "memoBody" }).appendTo(memoContainer)
  1291.  
  1292. //各div
  1293. var logArea = $("<div></div>", { id: "logArea" }).appendTo(memoBody)
  1294. var voteArea = $("<div></div>", { id: "voteArea" }).appendTo(memoBody)
  1295. var playerInfoArea = $("<div></div>", { id: "playerInfoArea" }).appendTo(logArea)
  1296. var buttonArea = $("<div></div>", { id: "buttonArea" }).appendTo(logArea)
  1297. var discussLogArea = $("<div></div>", { id: "discussLogArea" }).appendTo(logArea)
  1298.  
  1299. //テーブル
  1300. var playerInfoTable = $("<table>", { id: "playerInfoTable" }).appendTo(playerInfoArea)
  1301. var discussLogTable = $("<table>", { id: "discussLogTable" }).appendTo(discussLogArea)
  1302. var voteTable = $("<table>", { id: "voteTable" }).appendTo(voteArea)
  1303. var summaryTable = $("<table>", { id: "summaryTable" }).appendTo(voteArea)
  1304.  
  1305. //観戦時のみ自動更新ボタン
  1306. if ($("td.CLSTD01").eq(1).text() == "◆ 再表示") {
  1307. var onoff = data.isAutoReload ? "ON" : "OFF"
  1308. floatButtonArea.append("<div><a id='autoReload'>自動更新:" + onoff + "</a></div>")
  1309. if (data.isAutoReload) setAutoReload()
  1310.  
  1311. $("#autoReload").click(function () {
  1312. data.isAutoReload = !data.isAutoReload
  1313. save()
  1314. var onoff = data.isAutoReload ? "ON" : "OFF"
  1315. $("#autoReload").text("自動更新:" + onoff)
  1316. popupMessage("自動更新を" + onoff + "にしました。")
  1317.  
  1318. if (data.isAutoReload) {
  1319. setAutoReload()
  1320. } else {
  1321. clearTimeout(autoReloadFlg)
  1322. }
  1323. })
  1324. }
  1325.  
  1326. floatButtonArea.append(
  1327. [
  1328. "<div id='toolArea'><a>ツール</a>",
  1329. "<div id='toolArea_hid'>",
  1330. "<a id='tool1'>四桁乱数</a>",
  1331. "<a id='tool2'>乱数表</a>",
  1332. "<a id='tool3'>役職一覧と丸数字</a>",
  1333. "<a id='dispcaspe'>きゃすぺ</a>",
  1334. "<a id='dispsetting'>設定</a>",
  1335. "<a id='dispcolorsetting'>色設定</a></div>",
  1336. "</div>",
  1337. ].join("\n")
  1338. )
  1339. floatButtonArea.append("<div><a id='toggleButton'>メモ表示/非表示</a></div>")
  1340.  
  1341. //共通のボタン
  1342. memoMenu.append("<div class='button' id='importButton'>ログの取り込み</div>")
  1343. memoMenu.append("<div class='button' id='resetButton'>リセット</div>")
  1344. memoMenu.append("<div class='button' id='reloadButton'>更新</div>")
  1345.  
  1346. //タブ
  1347. memoTab.append("<div class='tab active' id='logDispButton' data-value='log'>発言ログ</div>")
  1348. memoTab.append("<div class='tab' id='voteDispButton' data-value='vote'>投票履歴</div>")
  1349.  
  1350. //各ブロックのボタン
  1351. buttonArea.append(
  1352. [
  1353. "<div>絞り込み",
  1354. "<div class='select filter' id='showAllButton' data-value='off'>全員表示</div>",
  1355. "<div class='select filter' id='showAliveButton' data-value='on'>生存+役職のみ</div>",
  1356. "</div>",
  1357. ].join("")
  1358. )
  1359. buttonArea.append(
  1360. [
  1361. "<div>役職入力",
  1362. "<div class='select inputmode' id='inputnoneButton' data-value='none'>なし</div>",
  1363. "<div class='select inputmode' id='inputsimpleButton' data-value='simple'>最新のみ</div>",
  1364. "<div class='select inputmode' id='inputfullButton' data-value='full'>全日</div>",
  1365. "</div>",
  1366. ].join("")
  1367. )
  1368.  
  1369. var settingTable = $("<table></table>", { id: "settingtable" }).appendTo(settingArea)
  1370. settingArea.append(
  1371. `<div class="closebutton"><input type="button" onclick="document.getElementById('setting').style.display='none';" value='閉じる'></div>`
  1372. )
  1373.  
  1374. for (var k in setting) {
  1375. var item = setting[k]
  1376. var tr = new Tr()
  1377. tr.add(item.name)
  1378. tr.add(createSelectBox(item.option, item.value, { id: k }))
  1379. tr.appendTo(settingTable)
  1380. }
  1381.  
  1382. var colorSettingTable = $("<table></table>", { id: "settingtable" }).appendTo(colorSettingArea)
  1383. colorSettingArea.append(
  1384. `<div class="closebutton"><input type="button" onclick="document.getElementById('colorSetting').style.display='none';" value='閉じる'></div>`
  1385. )
  1386.  
  1387. for (k in colorSetting) {
  1388. item = colorSetting[k]
  1389. tr = new Tr()
  1390. tr.add(item.name)
  1391. tr.add(createSelectBox(item.option, item.value, { id: "color_" + k }))
  1392. tr.appendTo(colorSettingTable)
  1393. }
  1394.  
  1395. caspe.html(
  1396. [
  1397. "キーワード:<input type='text' id='caspequery'>数:<input type='number' id='caspenum' value='1'><input type='button' id='castaspellonme' value='きゃすぺ'>",
  1398. "<div id='casperesult'></div>",
  1399. "<input type='button' id='changeicon' value='選択したアイコンを設定'>",
  1400. "<input type='hidden' id='iconno' value=''>",
  1401. `<div class="closebutton"><input type='button' onclick='document.getElementById("caspe").style.display = "none";' value='閉じる'></div>`,
  1402. ].join("\n")
  1403. )
  1404.  
  1405. //**********************************************
  1406. // ロードが完了したら仕込み
  1407. //**********************************************
  1408.  
  1409. $(function () {
  1410. playertable = $("table").eq(1)
  1411. textareatable = $("table[cellspacing=0]").eq(-1)
  1412. discusstable = $("table[cellpadding=0]").not("table.CLSTABLE2").last()
  1413. infotable = $("table[cellspacing=0]").eq(0)
  1414. commandtable = $("table[cellspacing=0]").eq(-2)
  1415. textarea = $("textarea").eq(0)
  1416. body = $("body")
  1417.  
  1418. var voicebutton =
  1419. "<td class='voiceloud'><div class='voice' data-value='MSG'>普</div><div class='voice' data-value='MSG2'><strong>強</strong></div><div class='voice' data-value='MSG3'><span style='color:#6666ee;'>弱</span></div></td>"
  1420. var submitbutton =
  1421. "<td><input type='submit' value='行動/更新' style='height:100px; width:150px;'></td>"
  1422. textareatable.find("td:last").after(submitbutton).after(voicebutton)
  1423.  
  1424. switchInputMode()
  1425. switchAliveFilter()
  1426.  
  1427. $("#toggleButton").on("click", () => {
  1428. memoContainer.toggle()
  1429. })
  1430. $("#importButton").on("click", function () {
  1431. importLog()
  1432. refresh()
  1433. })
  1434. $("div.tab").on("click", function () {
  1435. switchDispArea(this)
  1436. })
  1437. $("#resetButton").on("click", function () {
  1438. if (window.confirm("ログをすべてリセットします。本当によろしいですか?")) {
  1439. reset()
  1440. getToday()
  1441. refresh()
  1442. }
  1443. })
  1444. $("#reloadButton").on("click", function () {
  1445. textarea.val("")
  1446. document.forms[0].submit()
  1447. })
  1448.  
  1449. $("div.select.filter").on("click", function () {
  1450. switchAliveFilter(this)
  1451. })
  1452.  
  1453. $("div.select.inputmode").on("click", function () {
  1454. switchInputMode(this)
  1455. })
  1456.  
  1457. $("#toolArea").hover(
  1458. () => {
  1459. $("#toolArea_hid").show()
  1460. },
  1461. () => {
  1462. $("#toolArea_hid").hide()
  1463. }
  1464. )
  1465. $("#tool1").on("click", () => {
  1466. setClipboard(makernd())
  1467. popupMessage("コピーしました:4桁乱数")
  1468. })
  1469. $("#tool2").on("click", () => {
  1470. updateplayerInfo()
  1471. setClipboard(makematrix(playerInfo.length))
  1472. popupMessage("コピーしました:乱数表")
  1473. })
  1474. $("#tool3").on("click", () => {
  1475. updateplayerInfo()
  1476. setClipboard(makerndjob(playerInfo.length))
  1477. popupMessage("コピーしました:役職一覧")
  1478. })
  1479. $("#dispcaspe").on("click", () => {
  1480. $("#caspe").show()
  1481. })
  1482. $("#dispsetting").on("click", () => {
  1483. $("#setting").show()
  1484. })
  1485. $("#dispcolorsetting").on("click", () => {
  1486. $("#colorSetting").show()
  1487. })
  1488. $("#setting select").on("change", function () {
  1489. setting[$(this).attr("id")].value = $(this).val()
  1490. save()
  1491. })
  1492. $("#colorSetting select").on("change", function () {
  1493. let id = $(this).attr("id").slice(6)
  1494. colorSetting[id].value = $(this).val()
  1495. save()
  1496. setNameColor()
  1497. })
  1498. $("#castaspellonme").on("click", function () {
  1499. castASpellOnMe()
  1500. })
  1501. $("#changeicon").on("click", function () {
  1502. var no = $("#iconno").val()
  1503. if (no == "") return false
  1504. if (no - 0 > 4674) no = "/../../imgbbs/img/" + no
  1505. editSpeakField(no)
  1506. $("select").eq(0).val("BCONCHG")
  1507. document.forms[0].submit()
  1508. })
  1509.  
  1510. textarea.focus()
  1511.  
  1512. $("div.voice").click(function () {
  1513. $("select").eq(0).val($(this).data("value"))
  1514. $("div.voice").removeClass("voice_selected")
  1515. $(this).addClass("voice_selected")
  1516. })
  1517.  
  1518. $(window).on("keydown", function (e) {
  1519. if (e.keyCode == 27) {
  1520. memoContainer.hide()
  1521. }
  1522. })
  1523.  
  1524. if (localStorage.debug == "on") {
  1525. memoMenu.append("<div class='button' id='debugButton'>デバッグ用</div>")
  1526. $("#debugButton").click(() => {
  1527. console.log(data, today)
  1528. })
  1529. }
  1530.  
  1531. getToday()
  1532. dispSuggest()
  1533. highlightDeathnote()
  1534.  
  1535. if (setting.auto_import_log.value != "none") setAutoImportLog()
  1536. if (setting.alert_vote.value == "yes") setAlertVote()
  1537. if (setting.send_support.value != "none") receiveKeyResponse()
  1538. if (setting.coloringName.value == "yes") setNameColor()
  1539. if (data.villageno != getVillageno()) reset()
  1540.  
  1541. refresh()
  1542.  
  1543. if (!localStorage.memoVersion || localStorage.memoVersion != "1.4.2") {
  1544. localStorage.memoVersion = "1.5.0"
  1545. var notice = $("<div></div>", { id: "notice" }).appendTo(body)
  1546. /*
  1547. notice.attr("style","position:fixed;left:calc(50% - 200px);bottom:calc(50% - 100px); width:400px; height:200px;box-shadow: 0 3px 5px rgba(0, 0, 0, 0.4); border-top:16px solid var(--theme-color); background-color:#efefef; padding:10px; font-size:10pt;")
  1548. notice.html("<span style='font-size:12pt'>ウドメモver1.4に伴うお知らせ</span><br>未投票時にメモを見ながら投票できる機能を追加しましたが、この機能は<b>テストできていません。</b>必ず投票状態になったことを<b>目視確認</b>してください。また正常に動かなかった場合は教えてね(はーと)<br>")
  1549. notice.append($("<input>",{on:{click:function(){$("#notice").hide();}}, value:"表示しない", type:"button"}))
  1550. */
  1551. }
  1552. })
  1553. })(jQuery)