diff --git a/ddr@asphyxia/README.md b/ddr@asphyxia/README.md new file mode 100644 index 0000000..620ef90 --- /dev/null +++ b/ddr@asphyxia/README.md @@ -0,0 +1,18 @@ +# Dance Dance Revolution + +![Version](https://img.shields.io/badge/Version-v1.0.0-brightgreen?style=for-the-badge) + +--- + +Supported version + +- Dance Dance Revolution A20 +- Dance Dance Revolution A + +--- + +Changelogs + +**v1.0.0** + +- Initial release diff --git a/ddr@asphyxia/handlers/common.ts b/ddr@asphyxia/handlers/common.ts new file mode 100644 index 0000000..f3afdf1 --- /dev/null +++ b/ddr@asphyxia/handlers/common.ts @@ -0,0 +1,18 @@ +export const eventLog: EPR = (info, data, send) => { + return send.object({ + gamesession: K.ITEM("s64", BigInt(1)), + logsendflg: K.ITEM("s32", 0), + logerrlevel: K.ITEM("s32", 0), + evtidnosendflg: K.ITEM("s32", 0) + }); +}; + +export const convcardnumber: EPR = (info, data, send) => { + return send.object({ + result: K.ITEM("s32", 0), + + data: { + card_number: K.ITEM("str", $(data).str("data.card_id").split("|")[0]) + } + }); +}; diff --git a/ddr@asphyxia/handlers/usergamedata.ts b/ddr@asphyxia/handlers/usergamedata.ts new file mode 100644 index 0000000..1d513c6 --- /dev/null +++ b/ddr@asphyxia/handlers/usergamedata.ts @@ -0,0 +1,275 @@ +import { CommonOffset, LastOffset, OptionOffset, Profile } from "../models/profile"; +import { formatCode } from "../utils"; +import { Score } from "../models/score"; +import { Ghost } from "../models/ghost"; + +enum GameStyle { + SINGLE, + DOUBLE, + VERSUS +} + +export const usergamedata: EPR = async (info, data, send) => { + const mode = $(data).str("data.mode"); + const refId = $(data).str("data.refid"); + + switch (mode) { + case "userload": + return send.object(await userload(refId)); + case "usernew": + return send.object(await usernew(refId, data)); + case "usersave": + return send.object(await usersave(refId, data)); + case "rivalload": + return send.object(await rivalload(refId, data)); + case "ghostload": + return send.object(await ghostload(refId, data)); + case "inheritance": + return send.object(inheritance(refId)); + default: + return send.deny(); + } +}; + +const userload = async (refId: string) => { + let resObj = { + result: K.ITEM("s32", 0), + is_new: K.ITEM("bool", false), + music: [], + eventdata: [] + }; + + if (!refId.startsWith("X000")) { + const profile = await DB.FindOne(refId, { collection: "profile" }); + + if (!profile) resObj.is_new = K.ITEM("bool", true); + + const scores = await DB.Find(refId, { collection: "score" }); + + for (const score of scores) { + const note = []; + + for (let i = 0; i < 9; i++) { + if (score.difficulty !== i) { + note.push({ + count: K.ITEM("u16", 0), + rank: K.ITEM("u8", 0), + clearkind: K.ITEM("u8", 0), + score: K.ITEM("s32", 0), + ghostid: K.ITEM("s32", 0) + }); + } else { + note.push({ + count: K.ITEM("u16", 1), + rank: K.ITEM("u8", score.rank), + clearkind: K.ITEM("u8", score.clearKind), + score: K.ITEM("s32", score.score), + ghostid: K.ITEM("s32", score.songId) + }); + } + } + + resObj.music.push({ + mcode: K.ITEM("u32", score.songId), + note + }); + } + + resObj["grade"] = { + single_grade: K.ITEM("u32", profile.singleGrade || 0), + dougle_grade: K.ITEM("u32", profile.doubleGrade || 0) + }; + } + + return resObj; +}; + +const usernew = async (refId: string, data: any) => { + const shopArea = $(data).str("data.shoparea", ""); + + let profile = await DB.FindOne(refId, { collection: "profile" }); + + if (!profile) { + profile = (await DB.Upsert(refId, { collection: "profile" }, { + collection: "profile", + ddrCode: _.random(1, 99999999), + shopArea + })).docs[0]; + } + + return { + result: K.ITEM("s32", 0), + seq: K.ITEM("str", formatCode(profile.ddrCode)), + code: K.ITEM("s32", profile.ddrCode), + shoparea: K.ITEM("str", profile.shopArea), + }; +}; + +const usersave = async (refId: string, serverData: any) => { + const profile = await DB.FindOne(refId, { collection: "profile" }); + + if (profile) { + const data = $(serverData).element("data"); + const notes = data.elements("note"); + const events = data.elements("event"); + + const common = profile.usergamedata.COMMON.strdata.split(","); + const option = profile.usergamedata.OPTION.strdata.split(","); + const last = profile.usergamedata.LAST.strdata.split(","); + + if (data.bool("isgameover")) { + const style = data.number("playstyle"); + + if (style === GameStyle.DOUBLE) { + common[CommonOffset.DOUBLE_PLAYS] = (parseInt(common[CommonOffset.DOUBLE_PLAYS]) + 1) + ""; + } else { + common[CommonOffset.SINGLE_PLAYS] = (parseInt(common[CommonOffset.SINGLE_PLAYS]) + 1) + ""; + } + + common[CommonOffset.TOTAL_PLAYS] = (+common[CommonOffset.DOUBLE_PLAYS]) + (+common[CommonOffset.SINGLE_PLAYS]) + ""; + + const workoutEnabled = !!+common[CommonOffset.WEIGHT_DISPLAY]; + const workoutWeight = +common[CommonOffset.WEIGHT]; + + if (workoutEnabled && workoutWeight > 0) { + let total = 0; + + for (const note of notes) { + total = total + note.number("calorie", 0); + } + + last[LastOffset.CALORIES] = total + ""; + } + + for (const event of events) { + const eventId = event.number("eventid", 0); + const eventType = event.number("eventtype", 0); + if (eventId === 0 || eventType === 0) continue; + + const eventCompleted = event.number("comptime") !== 0; + const eventProgress = event.number("savedata"); + + if (!profile.events) profile.events = {}; + profile.events[eventId] = { + completed: eventCompleted, + progress: eventProgress + }; + } + + const gradeNode = data.element("grade"); + + if (gradeNode) { + const single = gradeNode.number("single_grade", 0); + const double = gradeNode.number("double_grade", 0); + + profile.singleGrade = single; + profile.doubleGrade = double; + } + } + + let scoreData: KDataReader | null; + let stageNum = 0; + + for (const note of notes) { + if (note.number("stagenum") > stageNum) { + scoreData = note; + stageNum = note.number("stagenum"); + } + } + + if (scoreData) { + const songId = scoreData.number("mcode"); + const difficulty = scoreData.number("notetype"); + const rank = scoreData.number("rank"); + const clearKind = scoreData.number("clearkind"); + const score = scoreData.number("score"); + const maxCombo = scoreData.number("maxcombo"); + const ghostSize = scoreData.number("ghostsize"); + const ghost = scoreData.str("ghost"); + + option[OptionOffset.SPEED] = scoreData.number("opt_speed").toString(16); + option[OptionOffset.BOOST] = scoreData.number("opt_boost").toString(16); + option[OptionOffset.APPEARANCE] = scoreData.number("opt_appearance").toString(16); + option[OptionOffset.TURN] = scoreData.number("opt_turn").toString(16); + option[OptionOffset.STEP_ZONE] = scoreData.number("opt_dark").toString(16); + option[OptionOffset.SCROLL] = scoreData.number("opt_scroll").toString(16); + option[OptionOffset.ARROW_COLOR] = scoreData.number("opt_arrowcolor").toString(16); + option[OptionOffset.CUT] = scoreData.number("opt_cut").toString(16); + option[OptionOffset.FREEZE] = scoreData.number("opt_freeze").toString(16); + option[OptionOffset.JUMP] = scoreData.number("opt_jump").toString(16); + option[OptionOffset.ARROW_SKIN] = scoreData.number("opt_arrowshape").toString(16); + option[OptionOffset.FILTER] = scoreData.number("opt_filter").toString(16); + option[OptionOffset.GUIDELINE] = scoreData.number("opt_guideline").toString(16); + option[OptionOffset.GAUGE] = scoreData.number("opt_gauge").toString(16); + option[OptionOffset.COMBO_POSITION] = scoreData.number("opt_judgepriority").toString(16); + option[OptionOffset.FAST_SLOW] = scoreData.number("opt_timing").toString(16); + + await DB.Upsert(refId, { + collection: "score", + songId, + difficulty + }, { + $set: { + rank, + clearKind, + score, + maxCombo + } + }); + + await DB.Upsert(refId, { + collection: "ghost", + songId, + difficulty + }, { + $set: { + ghostSize, + ghost + } + }); + } + + await DB.Update(refId, { collection: "profile" }, { + $set: { + "usergamedata.COMMON.strdata": common.join(","), + "usergamedata.OPTION.strdata": option.join(","), + "usergamedata.LAST.strdata": last.join(","), + } + }); + } + + return { + result: K.ITEM("s32", 0) + }; +}; + +const rivalload = (refId: string, data: any) => { + const loadFlag = $(data).number("data.loadflag"); + + const record = []; + + return { + result: K.ITEM("s32", 0), + + data: { + recordtype: K.ITEM("s32", loadFlag), + record + } + }; +}; + +const ghostload = (refId: string, data: any) => { + const ghostdata = {}; + + return { + result: K.ITEM("s32", 0), + ghostdata + }; +}; + +const inheritance = (refId: string) => { + return { + result: K.ITEM("s32", 0), + InheritanceStatus: K.ITEM("s32", 1) + }; +}; diff --git a/ddr@asphyxia/handlers/usergamedata_recv.ts b/ddr@asphyxia/handlers/usergamedata_recv.ts new file mode 100644 index 0000000..1508bae --- /dev/null +++ b/ddr@asphyxia/handlers/usergamedata_recv.ts @@ -0,0 +1,45 @@ +import { Profile } from "../models/profile"; + +export const usergamedata_recv: EPR = async (info, data, send) => { + const refId = $(data).str("data.refid"); + const profile = await DB.FindOne(refId, { collection: "profile" }); + + let recordNum = 0; + const record = []; + + const d = []; + const types = $(data).str("data.recv_csv").split(",").filter((_, i) => (i % 2 === 0)); + + for (const type of types) { + let strdata = ""; + let bindata = ""; + + if (profile) { + strdata = profile.usergamedata[type]["strdata"]; + bindata = profile.usergamedata[type]["bindata"]; + + if (type === "OPTION") { + const split = strdata.split(","); + + split[0] = U.GetConfig("save_option") ? "1" : "0"; + + strdata = split.join(","); + } + } + + d.push({ + ...K.ITEM("str", !profile ? strdata : Buffer.from(strdata).toString("base64")), + ...profile && { bin1: K.ITEM("str", Buffer.from(bindata).toString("base64")) } + }); + recordNum++; + } + record.push({ d }); + + return send.object({ + result: K.ITEM("s32", 0), + player: { + record, + record_num: K.ITEM("u32", recordNum) + } + }); +}; diff --git a/ddr@asphyxia/handlers/usergamedata_send.ts b/ddr@asphyxia/handlers/usergamedata_send.ts new file mode 100644 index 0000000..77014c1 --- /dev/null +++ b/ddr@asphyxia/handlers/usergamedata_send.ts @@ -0,0 +1,31 @@ +import { Profile } from "../models/profile"; + +export const usergamedata_send: EPR = async (info, data, send) => { + const refId = $(data).str("data.refid"); + + const profile = await DB.FindOne(refId, { collection: "profile" }); + if (!profile) return send.deny(); + + for (const record of $(data).elements("data.record.d")) { + const decodeStr = Buffer.from(record.str("", ""), "base64").toString("ascii"); + const decodeBin = Buffer.from(record.str("bin1", ""), "base64").toString("ascii"); + + const strdata = decodeStr.split(","); + const type = Buffer.from(strdata[1]).toString("utf-8"); + + if (!profile.usergamedata) profile.usergamedata = {}; + if (!profile.usergamedata[type]) profile.usergamedata[type] = {}; + profile.usergamedata[type] = { + strdata: strdata.slice(2, -1).join(","), + bindata: decodeBin + }; + } + + try { + await DB.Update(refId, { collection: "profile" }, profile); + + return send.object({ result: K.ITEM("s32", 0) }); + } catch { + return send.deny(); + } +}; diff --git a/ddr@asphyxia/index.ts b/ddr@asphyxia/index.ts new file mode 100644 index 0000000..d74eb1b --- /dev/null +++ b/ddr@asphyxia/index.ts @@ -0,0 +1,135 @@ +import { convcardnumber, eventLog } from "./handlers/common"; +import { usergamedata } from "./handlers/usergamedata"; +import { usergamedata_recv } from "./handlers/usergamedata_recv"; +import { usergamedata_send } from "./handlers/usergamedata_send"; +import { CommonOffset, OptionOffset, Profile } from "./models/profile"; + +export function register() { + R.GameCode("MDX"); + + R.Config("save_option", { + name: "Save option", + desc: "Gets the previously set options as they are.", + default: true, + type: "boolean" + }); + + R.Route("playerdata.usergamedata_advanced", usergamedata); + R.Route("playerdata.usergamedata_recv", usergamedata_recv); + R.Route("playerdata.usergamedata_send", usergamedata_send); + + R.Route("system.convcardnumber", convcardnumber); + R.Route("eventlog.write", eventLog); + + R.WebUIEvent("updateName", async ({ refid, name }) => { + let strdata: Profile | string[] = await DB.FindOne(refid, { collection: "profile" }); + + if (strdata) { + strdata = strdata.usergamedata.COMMON.strdata.split(","); + strdata[CommonOffset.NAME] = name; + await DB.Update(refid, { collection: "profile" }, { + $set: { + "usergamedata.COMMON.strdata": strdata.join(",") + } + }); + } + }); + + R.WebUIEvent("updateWeight", async ({ refid, weight }) => { + let strdata: Profile | string[] = await DB.FindOne(refid, { collection: "profile" }); + + if (strdata) { + strdata = strdata.usergamedata.COMMON.strdata.split(","); + strdata[CommonOffset.WEIGHT] = weight; + await DB.Update(refid, { collection: "profile" }, { + $set: { + "usergamedata.COMMON.strdata": strdata.join(",") + } + }); + } + }); + + R.WebUIEvent("updateDisplayCalories", async ({ refid, selected }) => { + let strdata: Profile | string[] = await DB.FindOne(refid, { collection: "profile" }); + + if (strdata) { + strdata = strdata.usergamedata.COMMON.strdata.split(","); + strdata[CommonOffset.WEIGHT_DISPLAY] = selected; + await DB.Update(refid, { collection: "profile" }, { + $set: { + "usergamedata.COMMON.strdata": strdata.join(",") + } + }); + } + }); + + R.WebUIEvent("updateArrowSkin", async ({ refid, selected }) => { + let strdata: Profile | string[] = await DB.FindOne(refid, { collection: "profile" }); + + if (strdata) { + strdata = strdata.usergamedata.OPTION.strdata.split(","); + strdata[OptionOffset.ARROW_SKIN] = selected; + await DB.Update(refid, { collection: "profile" }, { + $set: { + "usergamedata.OPTION.strdata": strdata.join(",") + } + }); + } + }); + + R.WebUIEvent("updateGuideline", async ({ refid, selected }) => { + let strdata: Profile | string[] = await DB.FindOne(refid, { collection: "profile" }); + + if (strdata) { + strdata = strdata.usergamedata.OPTION.strdata.split(","); + strdata[OptionOffset.GUIDELINE] = selected; + await DB.Update(refid, { collection: "profile" }, { + $set: { + "usergamedata.OPTION.strdata": strdata.join(",") + } + }); + } + }); + + R.WebUIEvent("updateFilter", async ({ refid, selected }) => { + let strdata: Profile | string[] = await DB.FindOne(refid, { collection: "profile" }); + + if (strdata) { + strdata = strdata.usergamedata.OPTION.strdata.split(","); + strdata[OptionOffset.FILTER] = selected; + await DB.Update(refid, { collection: "profile" }, { + $set: { + "usergamedata.OPTION.strdata": strdata.join(",") + } + }); + } + }); + + R.WebUIEvent("updateJudgmentPriority", async ({ refid, selected }) => { + let strdata: Profile | string[] = await DB.FindOne(refid, { collection: "profile" }); + + if (strdata) { + strdata = strdata.usergamedata.OPTION.strdata.split(","); + strdata[OptionOffset.COMBO_POSITION] = selected; + await DB.Update(refid, { collection: "profile" }, { + $set: { + "usergamedata.OPTION.strdata": strdata.join(",") + } + }); + } + }); + + R.WebUIEvent("updateDisplayTiming", async ({ refid, selected }) => { + let strdata: Profile | string[] = await DB.FindOne(refid, { collection: "profile" }); + + if (strdata) { + strdata = strdata.usergamedata.OPTION.strdata.split(","); + strdata[OptionOffset.FAST_SLOW] = selected; + await DB.Update(refid, { collection: "profile" }, { + $set: { + "usergamedata.OPTION.strdata": strdata.join(",") + } + }); + } + }); +} diff --git a/ddr@asphyxia/models/ghost.ts b/ddr@asphyxia/models/ghost.ts new file mode 100644 index 0000000..264f9d0 --- /dev/null +++ b/ddr@asphyxia/models/ghost.ts @@ -0,0 +1,8 @@ +export interface Ghost { + collection: "ghost"; + + songId: number; + difficulty: number; + ghostSize: number; + ghost: string; +} diff --git a/ddr@asphyxia/models/profile.ts b/ddr@asphyxia/models/profile.ts new file mode 100644 index 0000000..3fc99e4 --- /dev/null +++ b/ddr@asphyxia/models/profile.ts @@ -0,0 +1,77 @@ +export enum CommonOffset { + AREA = 1, + SEQ_HEX = 1, + WEIGHT_DISPLAY = 3, + CHARACTER, + EXTRA_CHARGE, + TOTAL_PLAYS = 9, + SINGLE_PLAYS = 11, + DOUBLE_PLAYS, + WEIGHT = 17, + NAME = 25, + SEQ +} + +export enum OptionOffset { + SPEED = 1, + BOOST, + APPEARANCE, + TURN, + STEP_ZONE, + SCROLL, + ARROW_COLOR, + CUT, + FREEZE, + JUMP, + ARROW_SKIN, + FILTER, + GUIDELINE, + GAUGE, + COMBO_POSITION, + FAST_SLOW +} + +export enum LastOffset { + SONG = 3, + CALORIES = 10 +} + +export enum RivalOffset { + RIVAL_1_ACTIVE = 1, + RIVAL_2_ACTIVE, + RIVAL_3_ACTIVE, + RIVAL_1_DDRCODE = 9, + RIVAL_2_DDRCODE, + RIVAL_3_DDRCODE, +} + +export interface Profile { + collection: "profile"; + + ddrCode: number; + shopArea: string; + + singleGrade?: number; + doubleGrade?: number; + + events?: {}; + + usergamedata?: { + COMMON?: { + strdata?: string; + bindata?: string; + }; + OPTION?: { + strdata?: string; + bindata?: string; + }; + LAST?: { + strdata?: string; + bindata?: string; + }; + RIVAL?: { + strdata?: string; + bindata?: string; + }; + }; +} diff --git a/ddr@asphyxia/models/score.ts b/ddr@asphyxia/models/score.ts new file mode 100644 index 0000000..37e184e --- /dev/null +++ b/ddr@asphyxia/models/score.ts @@ -0,0 +1,49 @@ +export enum Difficulty { + SINGLE_BEGINNER, + SINGLE_BASIC, + SINGLE_DIFFICULT, + SINGLE_EXPERT, + SINGLE_CHALLENGE, + DOUBLE_BASIC, + DOUBLE_DIFFICULT, + DOUBLE_EXPERT, + DOUBLE_CHALLENGE +} + +export enum Rank { + AAA, + AA_PLUS, + AA, + AA_MINUS, + A_PLUS, + A, + A_MINUS, + B_PLUS, + B, + B_MINUS, + C_PLUS, + C, + C_MINUS, + D_PLUS, + D, + E +} + +export enum ClearKind { + NONE = 6, + GOOD_COMBO, + GREAT_COMBO, + PERPECT_COMBO, + MARVELOUS_COMBO +} + +export interface Score { + collection: "score"; + + songId: number; + difficulty: Difficulty; + rank: Rank; + clearKind: ClearKind; + score: number; + maxCombo: number; +} diff --git a/ddr@asphyxia/utils.ts b/ddr@asphyxia/utils.ts new file mode 100644 index 0000000..ba665a6 --- /dev/null +++ b/ddr@asphyxia/utils.ts @@ -0,0 +1,13 @@ +export function getVersion(info: EamuseInfo) { + const dateCode = parseInt(info.model.split(":")[4]); + + if (dateCode >= 2019022600 && dateCode <= 2020020300) return 10; + + return 0; +} + +export function formatCode(ddrCode: number) { + const pad = (ddrCode + "").padStart(8, "0"); + + return pad.replace(/^([0-9]{4})([0-9]{4})$/, "$1-$2"); +} diff --git a/ddr@asphyxia/webui/js/profile_settings.js b/ddr@asphyxia/webui/js/profile_settings.js new file mode 100644 index 0000000..76fb7c9 --- /dev/null +++ b/ddr@asphyxia/webui/js/profile_settings.js @@ -0,0 +1,49 @@ +$('#change-name').on('click', () => { + const name = $('#dancer_name').val().toUpperCase(); + + emit('updateName', { refid, name }).then(() => location.reload()); +}); + +$('#change-weight').on('click', () => { + const weight1 = $('#weight_1').val(); + const weight2 = $('#weight_2').val(); + const weight = weight1 + '.' + weight2; + + emit('updateWeight', { refid, weight }).then(() => location.reload()); +}); + +$('#change-display-calories').on('click', () => { + const selected = $('#display_calories option:selected').val(); + + emit('updateDisplayCalories', { refid, selected }).then(() => location.reload()); +}); + +$('#change-arrow-skin').on('click', () => { + const selected = $('#arrow_skin option:selected').val(); + + emit('updateArrowSkin', { refid, selected }).then(() => location.reload()); +}); + +$('#change-guideline').on('click', () => { + const selected = $('#guideline option:selected').val(); + + emit('updateGuideline', { refid, selected }).then(() => location.reload()); +}); + +$('#change-filter').on('click', () => { + const selected = $('#filter option:selected').val(); + + emit('updateFilter', { refid, selected }).then(() => location.reload()); +}); + +$('#change-judgment-priority').on('click', () => { + const selected = $('#judgment_priority option:selected').val(); + + emit('updateJudgmentPriority', { refid, selected }).then(() => location.reload()); +}); + +$('#change-display-timing').on('click', () => { + const selected = $('#display_timing option:selected').val(); + + emit('updateDisplayTiming', { refid, selected }).then(() => location.reload()); +}); diff --git a/ddr@asphyxia/webui/profile_settings.pug b/ddr@asphyxia/webui/profile_settings.pug new file mode 100644 index 0000000..050bdae --- /dev/null +++ b/ddr@asphyxia/webui/profile_settings.pug @@ -0,0 +1,147 @@ +//DATA// + profile: DB.FindOne(refid, { collection: "profile" }) + +- + const onOff = [ "Off", "On" ]; + const characters = [ "All Character Random", "Man Random", "Female Random", "Yuni", "Rage", "Afro", "Jenny", "Emi", "Baby-Lon", "Gus", "Ruby", "Alice", "Julio", "Bonnie", "Zero", "Rinon" ]; + const arrowSkins = [ "Normal", "X", "Classic", "Cyber", "Medium", "Small", "Dot" ]; + const guidelines = [ "Off", "Border", "Center" ]; + const filters = [ "Off", "Dark", "Darker", "Darkest" ]; + const judgmentPrioritys = [ "Judgment priority", "Arrow priority" ]; + +if (profile.usergamedata) + - + const common = profile.usergamedata.COMMON.strdata.split(","); + const option = profile.usergamedata.OPTION.strdata.split(","); + + const name = common[25]; + const weight = common[17]; + const displayCalories = parseInt(common[3]); + const character = parseInt(common[4]); + const arrowSkin = parseInt(option[11]); + const guideline = parseInt(option[13]); + const filter = parseInt(option[12]); + const judgmentPriority = parseInt(option[15]); + const displayTiming = parseInt(option[16]); + + div + .card + .card-header + p.card-header-title + span.icon + i.mdi.mdi-cog + | Profile Settings + + .card-content + .field.is-horizontal.has-addons + .field-label.is-normal + label.label Dancer Name + .field-body + p.control + input.input(type="text", id="dancer_name", pattern="[A-Z]{8}", maxlength=8, value=name) + p.control + a.button.is-primary#change-name Change + + .field.is-horizontal.has-addons + .field-label.is-normal + label.label Workout Weight + .field-body + p.control + input.input(type="number", id="weight_1", value=weight.split(".")[0]) + p.control + input.input(type="number", id="weight_2", value=weight.split(".")[1]) + p.control + a.button.is-primary#change-weight Change + + .field.is-horizontal.has-addons + .field-label.is-normal + label.label Workout Display Calories + .field-body + p.control + .select + select#display_calories + if (displayCalories === 1) + option(value=0) Off + option(value=1, selected) On + else + option(value=0, selected) Off + option(value=1) On + p.control + a.button.is-primary#change-display-calories Submit + + .field.is-horizontal.has-addons + .field-label.is-normal + label.label Arrow Skin + .field-body + p.control + .select + select#arrow_skin + each v, i in arrowSkins + if (arrowSkin === i) + option(value=i, selected) #{v} + else + option(value=i) #{v} + p.control + a.button.is-primary#change-arrow-skin Submit + + .field.is-horizontal.has-addons + .field-label.is-normal + label.label Guideline + .field-body + p.control + .select + select#guideline + each v, i in guidelines + if (guideline === i) + option(value=i, selected) #{v} + else + option(value=i) #{v} + p.control + a.button.is-primary#change-guideline Submit + + .field.is-horizontal.has-addons + .field-label.is-normal + label.label Filter concentration + .field-body + p.control + .select + select#filter + each v, i in filters + if (filter === i) + option(value=i, selected) #{v} + else + option(value=i) #{v} + p.control + a.button.is-primary#change-filter Submit + + .field.is-horizontal.has-addons + .field-label.is-normal + label.label Judgment display priority + .field-body + p.control + .select + select#judgment_priority + each v, i in judgmentPrioritys + if (judgmentPriority === i) + option(value=i, selected) #{v} + else + option(value=i) #{v} + p.control + a.button.is-primary#change-judgment-priority Submit + + .field.is-horizontal.has-addons + .field-label.is-normal + label.label Display Timing judgment + .field-body + p.control + .select + select#display_timing + each v, i in ["Off", "On"] + if (displayTiming === i) + option(value=i, selected) #{v} + else + option(value=i) #{v} + p.control + a.button.is-primary#change-display-timing Submit + +script(src="static/js/profile_settings.js")