-
Notifications
You must be signed in to change notification settings - Fork 0
/
Engine.py
207 lines (168 loc) · 11 KB
/
Engine.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# im too lazy to document the engine right now lol!! (you can probably see why...)
import Keymap
import pygame
import json
import Globals
def load(map, drawreceptors):
data = json.load(open(map, encoding="utf8"))
for note in data["hitObjects"]:
for kp in data["keyPositions"]:
if note["x"] == kp:
note["x"] = data["keyPositions"].index(kp)
if drawreceptors:
for i in range(0, int(data["keyCount"])):
Globals.receptors.append(Globals.Receptor((i * Globals.options.options["playfield"][data["keyCount"]-1][1] + Globals.options.options["playfield"][data["keyCount"]-1][2]),Globals.options.options["playfield"][data["keyCount"]-1][0],Keymap.GetKey(Globals.options.options["keybinds"][data["keyCount"]-1][i]),i))
return data
LnReleaseQueue = []
JudgementQueue = []
def Draw(window, map, keycount, dt):
# get from globals
noteimgs = Globals.images.noteimgs
receptorimgs = Globals.images.receptorimgs
receptorDimgs = Globals.images.receptorDimgs
lnheadimgs = Globals.images.lnheadimgs
lnbodyimgs = Globals.images.lnbodyimgs
lntailimgs = Globals.images.lntailimgs
misssound = Globals.sounds.misssound
hitpos = Globals.options.options["playfield"][keycount-1][0]
columnwidth = Globals.options.options["playfield"][keycount-1][1]
scrollspeed = Globals.options.options["scrollspeed"]
# Receptor Highlighting
for key in Globals.receptors:
if pygame.key.get_pressed()[key.keybind]:
window.blit(receptorDimgs[key.track], (key.x, key.y))
key.held = True
else:
window.blit(receptorimgs[key.track], (key.x, key.y))
key.held = False
key.heldafter = False
# Note Rendering
for note in map:
if note["time"] <= Globals.mapinfo.currenttime + ((Globals.options.options["screen_height"] + 50) / scrollspeed) and note["endTime"] > Globals.mapinfo.currenttime - ((Globals.options.options["screen_height"] + 50) / scrollspeed): # within screen bounds (roughly)
y = (Globals.mapinfo.currenttime - (note["time"] - 1)) / (note["time"] - (note["time"] - 1)) * scrollspeed
yLN = (Globals.mapinfo.currenttime - (note["endTime"] - 1)) / (note["time"] - (note["time"] - 1)) * scrollspeed + ((columnwidth/2) / scrollspeed)
# too far down, past bottom of screen so delete and reset combo since it's a miss
if yLN >= Globals.options.options["screen_height"]+50:
JudgementQueue.append([note, "miss", y, yLN, None])
if note in map: del map[map.index(note)]
if note["type"] == "note": window.blit(noteimgs[Globals.receptors[note["x"]].track], (Globals.receptors[note["x"]].x, y))
drewheldln = False
# Input Handling + Drawing LN
if Globals.receptors[note["x"]].held:
# Inside register area
if (y <= hitpos+columnwidth) and (y >= hitpos-columnwidth):
if note["type"] == "note" and not Globals.receptors[note["x"]].heldafter and not Globals.receptors[note["x"]].holdingln:
JudgementQueue.append([note, "hit", y, yLN, None])
Globals.receptors[note["x"]].heldafter = True
if note in map: del map[map.index(note)]
# hold note, and receptor is released
elif note["type"] == "hold" and not Globals.receptors[note["x"]].heldafter:
# size of ln is pos+
if (hitpos - yLN >= 0):
# size of ln can be pos+ after dt
if (note["time"] + dt <= note["endTime"]):
note["time"] += dt
# first hold check (not already let go and reholding)
if note["newCombo"] == False and not Globals.receptors[note["x"]].holdingln:
JudgementQueue.append([note, "hit", y, yLN , True])
LnReleaseQueue.append([note])
note["newCombo"] = True
lnobjS = pygame.transform.scale(lnbodyimgs[Globals.receptors[note["x"]].track], ((columnwidth/1.5), (hitpos - yLN))).convert_alpha()
window.blit(lnobjS, (Globals.receptors[note["x"]].x + (columnwidth/6), yLN + (columnwidth/2)))
window.blit(lntailimgs[Globals.receptors[note["x"]].track], (Globals.receptors[note["x"]].x + (columnwidth/6), yLN))
window.blit(lnheadimgs[Globals.receptors[note["x"]].track], (Globals.receptors[note["x"]].x, hitpos))
Globals.receptors[note["x"]].heldafter = False
Globals.receptors[note["x"]].holdingln = True
drewheldln = True # do not drawn a regular ln
else:
Globals.receptors[note["x"]].heldafter = True
Globals.receptors[note["x"]].holdingln = False
else:
Globals.receptors[note["x"]].heldafter = True
Globals.receptors[note["x"]].holdingln = False
if note in map: del map[map.index(note)] # so it looks better lol
if note["type"] == "hold" and not drewheldln:
lnobj = pygame.transform.scale(lnbodyimgs[Globals.receptors[note["x"]].track], ((columnwidth/1.5), (note["endTime"] - note["time"]) * scrollspeed)).convert_alpha()
window.blit(lnobj, (Globals.receptors[note["x"]].x + (columnwidth/6), yLN))
window.blit(lntailimgs[Globals.receptors[note["x"]].track], (Globals.receptors[note["x"]].x + (columnwidth/6), yLN))
window.blit(lnheadimgs[Globals.receptors[note["x"]].track], (Globals.receptors[note["x"]].x, y))
Globals.receptors[note["x"]].holdingln = False
# Release Handling
for note in LnReleaseQueue:
if not Globals.receptors[note[0]["x"]].held:
if note[0]["type"] == "hold" and note[0]["newCombo"]:
y = (Globals.mapinfo.currenttime - (note[0]["time"] - 1)) / (note[0]["time"] - (note[0]["time"] - 1)) * scrollspeed
yLN = (Globals.mapinfo.currenttime - (note[0]["endTime"] - 1)) / (note[0]["time"] - (note[0]["time"] - 1)) * scrollspeed + ((columnwidth/2) / scrollspeed)
JudgementQueue.append([note[0], "hit", y, yLN, False])
Globals.receptors[note[0]["x"]].holdingln = False
if note in LnReleaseQueue: del LnReleaseQueue[LnReleaseQueue.index(note)]
if hitpos - yLN <= columnwidth/2:
if note[0] in map: del map[map.index(note[0])]
# Update Judgements
for note in JudgementQueue:
if note[1] == "miss":
Globals.stats.combo = 0
Globals.stats.miss += 1
Globals.stats.hp -= 5
Globals.stats.latestjudge = "MISS"
pygame.mixer.Channel(1).play(misssound)
elif note[1] == "hit":
judge_y = ""
if note[0]["type"] == "note":
bad_range = columnwidth/1.013
good_range = columnwidth/1.15
great_range = columnwidth/1.36
perfect_range = columnwidth/2.14
marvelous_range = columnwidth/4.29
elif note[0]["type"] == "hold":
bad_range = columnwidth*2
good_range = columnwidth*2
great_range = columnwidth
perfect_range = columnwidth/1.66
marvelous_range = columnwidth/3
if note[0]["type"] == "note": judge_y = note[2]
elif note[0]["type"] == "hold" and note[4]: judge_y = note[2]
elif note[0]["type"] == "hold" and not note[4]: judge_y = note[3] - (columnwidth/2)
else: print("\033[91mjudgement fallback!"); judge_y = note[2] # this should like never occur unless a parse bug got by
if (judge_y <= hitpos+bad_range) and (judge_y >= hitpos-bad_range):
Globals.stats.combo += 1
Globals.stats.latestjudge = "BAD"
Globals.stats.score += 50 # 50
Globals.stats.bad += 1
Globals.stats.hp -= 3
if (judge_y <= hitpos+good_range) and (judge_y >= hitpos-good_range):
Globals.stats.latestjudge = "GOOD"
Globals.stats.score += 50 # 100
Globals.stats.bad -= 1
Globals.stats.good += 1
Globals.stats.hp += 1
if (judge_y <= hitpos+great_range) and (judge_y >= hitpos-great_range):
Globals.stats.latestjudge = "GREAT"
Globals.stats.score += 100 # 200
Globals.stats.good -= 1
Globals.stats.great += 1
Globals.stats.hp += 1
if (judge_y <= hitpos+perfect_range) and (judge_y >= hitpos-perfect_range):
Globals.stats.latestjudge = "PERFECT"
Globals.stats.score += 100 # 300
Globals.stats.great -= 1
Globals.stats.perf += 1
Globals.stats.hp += 3
if (judge_y <= hitpos+marvelous_range) and (judge_y >= hitpos-marvelous_range):
Globals.stats.latestjudge = "MARVELOUS"
Globals.stats.score += 50 # 350
Globals.stats.perf -= 1
Globals.stats.marv += 1
Globals.stats.hp += 1
else:
Globals.stats.latestjudge = "MISS"
Globals.stats.combo = 0
Globals.stats.miss += 1
Globals.stats.hp -= 5
pygame.mixer.Channel(1).play(misssound)
Globals.stats.acc = 100*(350*(Globals.stats.marv + Globals.stats.perf) + 200*(Globals.stats.great) + 100*(Globals.stats.good) + 50*(Globals.stats.bad)) / (350*(Globals.stats.marv + Globals.stats.perf + Globals.stats.great + Globals.stats.good + Globals.stats.bad + Globals.stats.miss))
Globals.stats.acc = round(Globals.stats.acc, 2)
if Globals.stats.acc > 100: Globals.stats.acc = 100
if Globals.stats.hp > 100: Globals.stats.hp = 100
if note in JudgementQueue: del JudgementQueue[JudgementQueue.index(note)]
Globals.mapinfo.playingmap = map