mirror of
https://github.com/qwerfd2/Groove_Coaster_2_Server.git
synced 2026-09-22 22:38:01 +03:00
Added minimum support for mission
This commit is contained in:
@@ -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():
|
||||
|
||||
@@ -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}
|
||||
]
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user