- ending screen for versus battles
- add date to saved scores - add file for tracking dnf runs
This commit is contained in:
parent
0b59b4fc29
commit
41fa64c553
|
@ -23,3 +23,5 @@ _autosave-*
|
|||
www/Scrapeboard_Cyber_Monday_auction.webp
|
||||
www/Scrapeboard_Cyber_Monday_auction_long.webp
|
||||
www/Scrapeboard_auction_flyer_with_stream.png
|
||||
resource/scores.txt
|
||||
resource/dnf.txt
|
||||
|
|
98
NS.py
98
NS.py
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# This is the main file containing all the Pygame code.
|
||||
|
||||
import argparse, pathlib, operator, subprocess, sys, os, socket, select, time, random
|
||||
import argparse, pathlib, operator, subprocess, sys, os, socket, select, time, random, datetime
|
||||
|
||||
# Auto-detect GPIO library
|
||||
try:
|
||||
|
@ -76,16 +76,23 @@ class NS(Game, Animation):
|
|||
|
||||
class Score:
|
||||
|
||||
def __init__(self, milliseconds=None, level_index=None):
|
||||
def __init__(self, milliseconds=None, level_index=None, date=None):
|
||||
self.milliseconds = milliseconds
|
||||
self.level_index = level_index
|
||||
if date is None:
|
||||
date = datetime.datetime.now()
|
||||
self.date = date
|
||||
|
||||
@classmethod
|
||||
def from_string(cls, line: str):
|
||||
milliseconds, level_index = (int(field) for field in line.strip().split())
|
||||
fields = line.strip().split()
|
||||
milliseconds, level_index = (int(field) for field in fields[:2])
|
||||
date = None
|
||||
if len(fields) > 2:
|
||||
date = datetime.datetime.fromisoformat(fields[2])
|
||||
if level_index == -1:
|
||||
level_index = None
|
||||
return cls(milliseconds, level_index)
|
||||
return cls(milliseconds, level_index, date)
|
||||
|
||||
@classmethod
|
||||
def level(cls, milliseconds: int, level_index: int):
|
||||
|
@ -122,7 +129,7 @@ class NS(Game, Animation):
|
|||
serialized_level_index = -1
|
||||
else:
|
||||
serialized_level_index = self.level_index
|
||||
return f"{self.milliseconds} {serialized_level_index}"
|
||||
return f"{self.milliseconds} {serialized_level_index} {datetime.datetime.isoformat(self.date, 'T')}"
|
||||
|
||||
def __str__(self):
|
||||
return self.formatted()
|
||||
|
@ -234,7 +241,8 @@ class NS(Game, Animation):
|
|||
"system":
|
||||
{
|
||||
"bool": ["minimize-load-time", "enable-level-select", "optimize-title-screen"],
|
||||
"int": ["lives-boss-rush-mode", "lives-level-select-mode", "max-seed"]
|
||||
"int": ["lives-boss-rush-mode", "lives-level-select-mode", "max-seed"],
|
||||
"path": ["dnf-file", "scores-file"]
|
||||
},
|
||||
"pads":
|
||||
{
|
||||
|
@ -357,10 +365,12 @@ class NS(Game, Animation):
|
|||
self.most_recent_score = None
|
||||
|
||||
# Add existing scores to the list from file
|
||||
with open(self.get_resource("scores"), "rt") as score_file:
|
||||
for line in score_file:
|
||||
if line.strip():
|
||||
self.scores.append(NS.Score.from_string(line))
|
||||
path = self.get_configuration("system", "scores-file")
|
||||
if os.path.exists(path):
|
||||
with open(path, "rt") as score_file:
|
||||
for line in score_file:
|
||||
if line.strip():
|
||||
self.scores.append(NS.Score.from_string(line))
|
||||
|
||||
# Draw the score sprites
|
||||
self.title.draw_scores()
|
||||
|
@ -487,6 +497,7 @@ class NS(Game, Animation):
|
|||
message = f"{status} {level}"
|
||||
elif self.boss.player_defeated:
|
||||
status = "lost"
|
||||
self.peers["localhost"].result = None
|
||||
message = status
|
||||
else:
|
||||
status = "complete"
|
||||
|
@ -540,7 +551,6 @@ class NS(Game, Animation):
|
|||
peer.level = int(level)
|
||||
peer.seed = int(seed)
|
||||
peer.status = status
|
||||
print(f"Received seed {peer.seed}")
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
|
@ -663,10 +673,16 @@ class NS(Game, Animation):
|
|||
score = NS.Score.level(milliseconds, level_index)
|
||||
self.scores.append(score)
|
||||
self.most_recent_score = score
|
||||
with open(self.get_resource("scores"), "wt") as score_file:
|
||||
for score in sorted(self.scores):
|
||||
if not score.blank():
|
||||
score_file.write(f"{score.serialize()}\n")
|
||||
|
||||
# Write scores to file
|
||||
try:
|
||||
with open(self.get_configuration("system", "scores-file"), "wt") as score_file:
|
||||
for score in sorted(self.scores):
|
||||
if not score.blank():
|
||||
score_file.write(f"{score.serialize()}\n")
|
||||
except:
|
||||
print("Error saving scores")
|
||||
|
||||
self.title.draw_scores()
|
||||
|
||||
def update(self):
|
||||
|
@ -972,7 +988,8 @@ class LevelSelect(Animation):
|
|||
self.halt(self.force_launch)
|
||||
self.get_game().pop_up("", clear=True)
|
||||
self.level_launched = True
|
||||
if self.get_game().count_players() > 1:
|
||||
self.opponents_at_launch = [peer for peer in self.get_game().peers.values() if peer.versus]
|
||||
if len(self.opponents_at_launch) > 1:
|
||||
for level_index in range(3):
|
||||
if level_index != self.level_index_selected:
|
||||
self.platforms[level_index].view.halt()
|
||||
|
@ -2996,6 +3013,14 @@ class Boss(Animation):
|
|||
self.level_sprite().set_frameset("normal")
|
||||
self.play(self.flash_player_damage)
|
||||
self.get_game().chemtrails.set_frameset("hurt")
|
||||
|
||||
# Record a play to the DNF file for analytics
|
||||
try:
|
||||
with open(self.get_configuration("system", "dnf-file"), "at") as dnf_file:
|
||||
dnf_file.write(f"{self.time_elapsed} {self.level_index} {datetime.datetime.isoformat(datetime.datetime.now(), 'T')}\n")
|
||||
except:
|
||||
print("Error saving DNF run to file")
|
||||
|
||||
self.player_defeated = not win
|
||||
self.kills += not win
|
||||
self.play(self.show_end_dialogue, delay=3000, play_once=True)
|
||||
|
@ -3576,18 +3601,18 @@ class Ending(Animation):
|
|||
foreground = get_boxed_surface(
|
||||
self.time_font.render(str(self.get_game().most_recent_score), False, (180, 150, 20), (255, 255, 255)).convert_alpha(),
|
||||
background=(255, 255, 255), padding=(38, 0))
|
||||
if self.rank() % 100 // 10 != 1:
|
||||
if self.rank() % 10 == 1:
|
||||
if self.rank()[0] % 100 // 10 != 1:
|
||||
if self.rank()[0] % 10 == 1:
|
||||
ordinal = "ST"
|
||||
elif self.rank() % 10 == 2:
|
||||
elif self.rank()[0] % 10 == 2:
|
||||
ordinal = "ND"
|
||||
elif self.rank() % 10 == 3:
|
||||
elif self.rank()[0] % 10 == 3:
|
||||
ordinal = "RD"
|
||||
else:
|
||||
ordinal = "TH"
|
||||
else:
|
||||
ordinal = "TH"
|
||||
rank = self.rank_font.render(f"{self.rank()}{ordinal}", False, (180, 150, 20), (255, 255, 255))
|
||||
rank = self.rank_font.render(f"{self.rank()[0]}{ordinal}", False, (180, 150, 20), (255, 255, 255))
|
||||
rank = pygame.transform.rotate(rank, 90)
|
||||
rank_rect = rank.get_rect()
|
||||
rank_rect.midleft = foreground.get_rect().midleft
|
||||
|
@ -3608,19 +3633,42 @@ class Ending(Animation):
|
|||
|
||||
def rank(self):
|
||||
"""
|
||||
Get the rank of the currently displaying score
|
||||
@return the rank of the currently displaying score as a tuple: (rank, total)
|
||||
"""
|
||||
rank = 0
|
||||
for score in sorted([score for score in self.get_game().scores if score.level_index == self.defeated_level_index]):
|
||||
level_scores = [score for score in self.get_game().scores if score.level_index == self.defeated_level_index and not score.blank()]
|
||||
for score in sorted(level_scores):
|
||||
rank += 1
|
||||
if score == self.get_game().most_recent_score:
|
||||
break
|
||||
return rank
|
||||
return rank, len(level_scores)
|
||||
|
||||
def start(self):
|
||||
dialogue = self.get_game().dialogue
|
||||
if self.get_configuration("system", "enable-level-select"):
|
||||
text = f"You vanquished my goon and got the #{self.rank()} rank! Well done, slime bag.\n"
|
||||
|
||||
# Create a message for versus mode
|
||||
if len(self.get_game().level_select.opponents_at_launch) > 1:
|
||||
|
||||
# Check if any peers had a faster time
|
||||
rank = 1
|
||||
for peer in self.get_game().level_select.opponents_at_launch:
|
||||
if peer.address != "localhost" and not peer.status == "playing" and peer.result is not None and \
|
||||
peer.result < self.get_game().most_recent_score.milliseconds:
|
||||
rank += 1
|
||||
|
||||
if rank == 1:
|
||||
text = (f"Congratulations on winning the battle and getting #{self.rank()[0]} out of {self.rank()[1]} overall!\n"
|
||||
"Well done, slime bag. ")
|
||||
else:
|
||||
total = len(self.get_game().level_select.opponents_at_launch)
|
||||
text = (f"You were #{rank} out of {total} in the battle, but you vanquished my goon and finished\n"
|
||||
f"#{self.rank()[0]} out of {self.rank()[1]} overall! Well done, slime bag. ")
|
||||
|
||||
# Create a message for single-player mode
|
||||
else:
|
||||
text = f"You vanquished my goon and got #{self.rank()[0]} out of {self.rank()[1]}! Well done, slime bag.\n"
|
||||
|
||||
if self.defeated_level_index == 2:
|
||||
dialogue.set_name("Tony")
|
||||
text += "You made your father proud today. I love you child."
|
||||
|
|
2
config
2
config
|
@ -41,6 +41,8 @@ lives-boss-rush-mode = 3
|
|||
lives-level-select-mode = 1
|
||||
optimize-title-screen = no
|
||||
max-seed = 2147483647
|
||||
dnf-file = resource/dnf.txt
|
||||
scores-file = resource/scores.txt
|
||||
|
||||
[network]
|
||||
peers =
|
||||
|
|
Loading…
Reference in New Issue