Added minimum support for mission

This commit is contained in:
UnitedAirforce
2025-01-28 14:12:59 +08:00
parent 30d3670e6e
commit a08377ad79
3 changed files with 231 additions and 29 deletions
+61 -29
View File
@@ -52,17 +52,22 @@ def encryptAES(data, key=AES_CBC_KEY, iv=AES_CBC_IV):
encryptedData = AES.new(key, AES.MODE_CBC, iv).encrypt(data)
return encryptedData.hex()
start_stages = [3,4,5,7,9,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,214]
start_stages = [7,23,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,88,89,90,91,92,93,94,95,96,97,98,99,214]
# 214 is tutorial song.
start_avatars = []
exclude_stage_exp_pre_100 = [0,1,2,6,8,10,11,12,13,14,15,16,17,18,19,20,21,53,74,75] # not used for now, just archiving
exclude_stage_exp = [121,134,166,167,168,169,170,215,225] # 134 and 170 unoccupied dummy tracks (filled with Departure -Remix-),
exclude_stage_exp = [121,134,166,167,168,169,170,213,214,215,225] # 134 and 170 unoccupied dummy tracks (filled with Departure -Remix-),
#121 (and 93-96 lady gaga songs) removed (can be enabled by patching stageParam:isAvailable, or change the last byte before next song's name - 1 from 01 to 03 in stage_param.dat.
# Rest are exp unlocked songs.
exclude_avatar_exp = [28,29]
try:
with open("exp_unlocked_songs.json", 'r', encoding="utf-8") as file:
exp_unlocked_songs = json.load(file)
except Exception as e:
print(f"An unexpected error occurred when loading exp_unlocked_songs.json: {e}")
special_titles = [1, 2, 4431, 4432, 4601, 4602, 4611, 4612, 4621, 4622, 4631, 4632, 5111, 5112, 5121, 5122, 5131, 5132, 10001, 10002, 20001, 20002, 20003, 20004, 20005, 20006, 30001, 30002, 40001, 40002, 50001, 50002, 60001, 60002, 70001, 70002, 80001, 80002, 90001, 90002, 100001, 100002, 110001, 110002, 120001, 120002, 130001, 130002, 140001, 140002, 140003, 140004, 150001, 150002, 150003, 150004, 160001, 160002, 160003, 160004, 170001, 170002, 170003, 170004, 180001, 180002, 180003, 180004, 190001, 190002, 190003, 190004, 200001, 200002, 200003, 200004, 210001, 210002, 210003, 210004, 210005, 210006, 210007, 210008, 210009, 210010, 210011, 210012, 210013, 210014, 240001, 240002, 240003, 240004, 240005, 240006, 240007, 240008, 240009, 240010, 240011, 240012]
god_titles = [220001, 220002, 220003, 220004, 220005, 220006, 220007, 220008, 220009, 220010, 220011, 220012, 220013, 220014, 220015, 220016, 220017, 220018, 220019, 220020, 220021, 220022, 220023, 220024, 220025, 220026, 220027, 220028, 220029, 220030, 220031, 220032, 220033, 220034, 220035, 220036, 220037, 220038, 220039, 220040, 220041, 220042, 220043, 220044, 220045, 220046, 220047, 220048, 220049, 220050, 220051, 220052, 220053, 220054, 220055, 220056, 220057, 220058, 220059, 220060, 220061, 220062, 220063, 220064, 220065, 220066, 220067, 220068, 220069, 220070, 220071, 220072, 220073, 220074, 220075, 220076, 220077, 220078, 220079, 220080, 220081, 220082, 220083, 220084, 220085, 220086, 220087, 220088, 220089, 220090, 220091, 220092, 220093, 220094, 220095, 220096, 220097, 220098, 220099, 220100, 220101, 220102]
@@ -480,13 +485,11 @@ def sync():
cursor.execute("""UPDATE daily_reward SET item = ? WHERE device_id = ?""", ("[]", device_id))
cursor.close()
# Add `my_avatar` elements to XML
for avatar_id in my_avatar:
avatar_elem = ET.Element("my_avatar")
avatar_elem.text = str(avatar_id)
root.append(avatar_elem)
# Add `my_stage` elements to XML
for stage_id in my_stage:
stage_elem = ET.Element("my_stage")
stage_id_elem = ET.Element("stage_id")
@@ -600,7 +603,6 @@ def result():
if row:
current_coin = row[0] if row[0] else 10
# Increment the coin value by 1
updated_coin = current_coin + coin_reward
cursor.execute("UPDATE daily_reward SET coin = ? WHERE device_id = ?", (updated_coin, device_id))
@@ -651,12 +653,10 @@ def result():
records = cursor.fetchall()
cursor.close()
if len(records) > 0:
# check to see if update is needed
last_row_id = records[0][0]
if (score > records[0][1]):
do_update_sid = True
else:
# create the record
do_insert = True
else:
with sqlite3.connect(DATABASE) as connection:
@@ -668,12 +668,10 @@ def result():
records = cursor.fetchall()
cursor.close()
if len(records) > 0:
# check to see if update is needed
last_row_id = records[0][0]
if (score > records[0][1]):
do_update_vid = True
else:
# create the record
do_insert = True
@@ -712,17 +710,30 @@ def result():
cursor.close()
connection.commit()
# Update player profile regardless
# Update player profile regardless. Check for exp unlocked songs too
with sqlite3.connect(DATABASE) as connection:
cursor = connection.cursor()
query_command = "SELECT my_stage FROM daily_reward WHERE device_id = ?"
cursor.execute(query_command, (device_id,))
result = cursor.fetchone()
my_stage = set(json.loads(result[0])) if result and result[0] else set(start_stages)
current_exp = int(stts.split(",")[0])
for song in exp_unlocked_songs:
if song["lvl"] <= current_exp:
my_stage.add(song["id"])
my_stage = sorted(my_stage)
update_command = """
UPDATE daily_reward SET lvl = ?, avatar = ? WHERE device_id = ?;
UPDATE daily_reward SET lvl = ?, avatar = ?, my_stage = ? WHERE device_id = ?;
"""
cursor.execute(update_command, (int(stts.split(",")[0]), int(avatar), device_id))
cursor.execute(update_command, (current_exp, int(avatar), json.dumps(my_stage), device_id))
cursor.close()
connection.commit()
with sqlite3.connect(DATABASE) as connection:
cursor = connection.cursor()
select_command = """
@@ -854,6 +865,9 @@ def web_shop_detail():
if (cnt_type == "1"):
song = song_list[cnt_id]
difficulty_levels = "/".join(map(str, song.get("difficulty_levels", [])))
song_stage_price = stage_price
if (len(song["difficulty_levels"]) == 6):
song_stage_price = stage_price * 2
html = f"""
<div class="image-container">
<img src="/files/image/icon/shop/{cnt_id}.jpg" alt="Item Image" style="width: 180px; height: 180px;" />
@@ -865,7 +879,7 @@ def web_shop_detail():
</div>
<div>
<img src="/files/web/coin_icon.png" class="coin-icon" style="width: 40px; height: 40px;" alt="Coin Icon" />
<span style="color: #FFFFFF; font-size: 44px; font-family: Hiragino Kaku Gothic ProN, sans-serif;">{stage_price}</span>
<span style="color: #FFFFFF; font-size: 44px; font-family: Hiragino Kaku Gothic ProN, sans-serif;">{song_stage_price}</span>
</div>
"""
@@ -917,8 +931,8 @@ def web_shop_detail():
<a href="wwic://web_shop?cnt_type={cnt_type}" class="bt_bg01" >Go Back</a>
</div>
"""
html_path = f"files/web_shop_detail.html"
with open(html_path, "r", encoding="utf-8") as file:
with open(f"files/web_shop_detail.html", "r", encoding="utf-8") as file:
html_content = file.read().format(text=html, coin=coin)
return html_content
@@ -947,12 +961,16 @@ def buy_by_coin():
# Process based on cnt_type
if cnt_type == "1":
if coin < stage_price:
song_stage_price = stage_price
if (len(song_list[cnt_id]["difficulty_levels"]) == 6):
song_stage_price = song_stage_price * 2
if coin < song_stage_price:
return fail_url
stages = set(json.loads(my_stage)) if my_stage else set()
if cnt_id not in stages:
coin -= stage_price
coin -= song_stage_price
stages.add(cnt_id)
else:
return fail_url
@@ -1037,8 +1055,7 @@ def ranking():
'''
html += "</ul>"
html_path = f"files/ranking.html"
with open(html_path, "r", encoding="utf-8") as file:
with open(f"files/ranking.html", "r", encoding="utf-8") as file:
html_content = file.read().format(text=html)
return html_content
@@ -1181,8 +1198,7 @@ def ranking_detail():
</a>
"""
html_path = f"files/ranking.html"
with open(html_path, "r", encoding="utf-8") as file:
with open(f"files/ranking.html", "r", encoding="utf-8") as file:
html_content = file.read().format(text=html)
return html_content
@@ -1279,8 +1295,7 @@ def status():
html += titles_html
html_path = f"files/status.html"
with open(html_path, "r", encoding="utf-8") as file:
with open(f"files/status.html", "r", encoding="utf-8") as file:
html_content = file.read().format(text=html)
return html_content
@@ -1324,11 +1339,28 @@ def set_title():
@app.route('/mission.php/', methods=['GET'])
def mission():
return inform_page("This feature is not available in Private Server.", 1)
global exp_unlocked_songs, song_list
@app.route('/mission_reward.php/', methods=['GET'])
def mission_reward():
return inform_page("This feature is not available in Private Server.", 1)
html = f"""<div class="f90 a_center pt50" >Play Music to level up and unlock free songs!<br>Songs can only be unlocked when you play online.</div><div class='mission-list'>"""
# Render the mission list
for song in exp_unlocked_songs:
song_id = song["id"]
level_required = song["lvl"]
song_name = song_list[song_id]["name_en"] if song_id < len(song_list) else "Unknown Song"
html += f"""
<div class="mission-row">
<div class="mission-level">Level {level_required}</div>
<div class="mission-song">{song_name}</div>
</div>
"""
html += "</div>"
with open(f"files/mission.html", "r", encoding="utf-8") as file:
html_content = file.read().format(text=html)
return html_content
@app.route('/name_reset/', methods=['POST'])
def name_reset():
+62
View File
@@ -0,0 +1,62 @@
[
{"id": 1, "lvl": 5},
{"id": 2, "lvl": 10},
{"id": 3, "lvl": 15},
{"id": 4, "lvl": 20},
{"id": 5, "lvl": 25},
{"id": 6, "lvl": 30},
{"id": 8, "lvl": 35},
{"id": 9, "lvl": 40},
{"id": 10, "lvl": 45},
{"id": 11, "lvl": 50},
{"id": 12, "lvl": 55},
{"id": 13, "lvl": 60},
{"id": 14, "lvl": 65},
{"id": 15, "lvl": 70},
{"id": 16, "lvl": 75},
{"id": 17, "lvl": 80},
{"id": 18, "lvl": 85},
{"id": 19, "lvl": 90},
{"id": 20, "lvl": 95},
{"id": 21, "lvl": 100},
{"id": 22, "lvl": 105},
{"id": 24, "lvl": 110},
{"id": 25, "lvl": 115},
{"id": 26, "lvl": 120},
{"id": 27, "lvl": 125},
{"id": 28, "lvl": 130},
{"id": 29, "lvl": 135},
{"id": 30, "lvl": 140},
{"id": 31, "lvl": 145},
{"id": 32, "lvl": 150},
{"id": 33, "lvl": 155},
{"id": 34, "lvl": 160},
{"id": 35, "lvl": 165},
{"id": 53, "lvl": 170},
{"id": 54, "lvl": 175},
{"id": 74, "lvl": 180},
{"id": 75, "lvl": 185},
{"id": 76, "lvl": 190},
{"id": 77, "lvl": 195},
{"id": 78, "lvl": 200},
{"id": 79, "lvl": 205},
{"id": 80, "lvl": 210},
{"id": 81, "lvl": 215},
{"id": 82, "lvl": 220},
{"id": 83, "lvl": 225},
{"id": 84, "lvl": 230},
{"id": 85, "lvl": 235},
{"id": 86, "lvl": 240},
{"id": 87, "lvl": 245},
{"id": 93, "lvl": 250},
{"id": 94, "lvl": 255},
{"id": 95, "lvl": 260},
{"id": 96, "lvl": 265},
{"id": 121, "lvl": 270},
{"id": 166, "lvl": 275},
{"id": 167, "lvl": 280},
{"id": 168, "lvl": 285},
{"id": 169, "lvl": 290},
{"id": 215, "lvl": 295},
{"id": 225, "lvl": 300}
]
+108
View File
@@ -0,0 +1,108 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta content="user-scalable=0" name="viewport" />
<style type="text/css">
body{{
background-color: #000000;
-webkit-text-size-adjust: none;
padding: 0px;
margin: 0 auto;
text-align:center;
color: #FFFFFF;
-webkit-text-size-adjust: auto;
-webkit-touch-callout:none;
-webkit-tap-highlight-color:rgba(255,255,0,0.4);
height: 100%;
font-family: Hiragino Kaku Gothic ProN,Hiragino Kaku Gothic Pro,Meiryo,Helvetica,Arial,sans-serif;
font-size: 34pt;
line-height: 36pt;
}}
.a_left{{text-align:left;}}
.a_center{{text-align:center;}}
.w100{{width:100%;}}
.d_ib{{display:inline-block;}}
.mb10p{{margin-bottom:10%;}}
.f90{{font-size:90%;}}
.pt50{{padding-top:50px;}}
#header {{
text-align: center;
background-color: #000000;
border-bottom: 2px solid #ffffff;
top: 0px;
width: 100%;
padding: 0px;
display: block;
z-index: 4;
position: fixed;
}}
div#wrapper{{
width: 100%;
position: relative;
z-index: 1;
}}
.wrapper_box{{
text-align:center;
margin-top:5%;
margin-bottom:-10%;
display: inline-block;
position: relative;
width: 100%;
}}
.ttl_height{{
height:40px;
margin:20px 0px;
}}
.bt_bg01 {{
background: url("/files/web/bt_bg01_640.gif");
background-color: transparent;
background-repeat: no-repeat;
background-size:cover;
padding: 10px;
display: block;
text-align:center;
font-size:70%;
width:380px;
height: 61px;
color: #DDDDDD;
margin: 20px auto;
}}
.mission-list {{
display: flex;
flex-direction: column;
width: 100%;
margin: 20px 0;
font-family: Arial, sans-serif;
}}
.mission-row {{
display: flex;
justify-content: space-between;
padding: 10px;
border-bottom: 1px solid #ddd;
}}
.mission-level {{
font-weight: bold;
color: #DDD;
}}
.mission-song {{
color: #EEE;
}}
</style>
</head>
<body>
<div id="header">
<img class="ttl_height" src="/files/web/ttl_mission.png" alt="MISSION" />
</div>
<div id="wrapper">
<div class="wrapper_box">
<div class="a_left w100 d_ib mb10p">
<br>{text}
</div>
</div>
</div>
</body>
</html>