forum

DM DOKURO - SAVE

posted
Total Posts
4
Topic Starter
Flowey
This beatmap was submitted using in-game submission on Saturday, May 21, 2016 at 12:02:38 PM

Artist: DM DOKURO
Title: SAVE
Source: UNDERTALE
Tags: toby radiation fox Asriel Dreemur Hopes Dreams
BPM: 180
Filesize: 9640kb
Play Time: 05:13
Difficulties Available:
  1. And then you'll lose to me again. And again. And again!!! (5.64 stars, 1085 notes)
Download: DM DOKURO - SAVE
Information: Scores/Beatmap Listing
---------------
This map contains Undertale spoilers!

WIP

The storyboard was made using osbpy.

The SB load does exceed 5 during two parts in the map. Each time only lasts about 0.1 seconds, so I don't think this is a problem.

[Storyboard Code]
storyboard.py
from osbpy import *
from math import *

beat = 333
start = 31

def introMovement(sprite, offset = 0):
sprite.loop(start, (21364-start)//(8*beat))
sprite.moveY(17, 0, 4*beat, 240 + offset, 245 + offset, True)
sprite.moveY(17, 4*beat, 8*beat, 245 + offset, 240 + offset, True)

def regularMovement(sprite, offsetX, offsetY, scaleY = 1, delay = 0):
sprite.loop(21364 + delay, (309364-21364)//(16*beat));
sprite.moveX(16, 0, 4*beat, 320 + offsetX, 120 + offsetX, True)
sprite.moveX(15, 4*beat, 8*beat, 120 + offsetX, 320 + offsetX, True)
sprite.moveX(16, 8*beat, 12*beat, 320 + offsetX, 520 + offsetX, True)
sprite.moveX(15, 12*beat, 16*beat, 520 + offsetX, 320 + offsetX, True)

sprite.loop(21364 + delay, (309364-21364)//(12*beat));
sprite.moveY(16, 0, 3*beat, 240 + offsetY, 240 + int(60 * scaleY) + offsetY, True)
sprite.moveY(15, 3*beat, 6*beat, 240 + int(60 * scaleY) + offsetY, 240 + offsetY, True)
sprite.moveY(16, 6*beat, 9*beat, 240 + offsetY, 240 - int(60 * scaleY) + offsetY, True)
sprite.moveY(15, 9*beat, 12*beat, 240 - int(60 * scaleY) + offsetY, 240 + offsetY, True)

def flash(s, alpha = 1):
s.loop(21364, (42697 - 21364)//beat + 1)
s.fade(0, 0, beat, alpha, 0, True)

s.loop(64030, (85364 - 64030)//beat + 1)
s.fade(0, 0, beat, alpha, 0, True)

s.loop(192030, (234697 - 192030)//beat + 1)
s.fade(0, 0, beat, alpha, 0, True)

s.loop(256030, (298697 - 256030)//beat)
s.fade(0, 0, beat, alpha, 0, True)

s.fade(0, 298697, 300030, alpha, 0.3 * alpha)
s.fade(0, 300030, 302697, 0.3 * alpha, alpha)
s.fade(0, 302697, 304030, alpha, 0)
flashTimes = [304030, 304197, 304530, 304697, 305030, 305197, 305530, 305697, 306030, 306364]

for i in flashTimes:
s.fade(0, i, i + beat//4, alpha, 0)

s.fade(0, 306697, 309364 - beat, alpha, 0)





removeBackground = osbject("undertale.png", "Background", "Centre", 320, 240)


frame_rate, music = wavfile.read("audio.wav")
music_channel0 = music[:, 0]
music_channel1 = music[:, 1]

'''
spectrum0, spec0_freqs, spec0_t, spec0_im = plt.specgram(music_channel0, NFFT=1024, Fs = frame_rate, noverlap=5, mode='magnitude')
spec0_max = plt.amax(spectrum0)
spec0_min = plt.amin(spectrum0)

spectrum1, spec1_freqs, spec1_t, spec1_im = plt.specgram(music_channel0, NFFT=1024, Fs = frame_rate, noverlap=5, mode='magnitude')
spec1_max = plt.amax(spectrum1)
spec1_min = plt.amin(spectrum1)
'''

def backgroundColor(s, offset = False):
offsetA = randint(-600, 600) if offset else 0
s.loop(21364 + offsetA, int((245364-21364)/(beat * 24)))
s.color(11, 0, beat * 8, 0, 0, 255, 255, 0, 0, True)
s.color(11, beat * 8, beat * 16, 255, 0, 0, 0, 126, 0, True)
s.color(11, beat * 16, beat * 24, 0, 126, 0, 0, 0, 255, True)

s.color(0, 245364, 248030, 0, 0, 255, 20, 20, 20)

rs = [255, 255, 255, 235, 156, 65, 1, 0, 0, 0, 0, 0, 0, 72, 193, 251]
gs = [36, 130, 221, 252, 239, 202, 180, 194, 225, 234, 130, 54, 3, 0, 0, 0]
bs = [0, 0, 0, 3, 13, 28, 57, 111, 187, 255, 213, 168, 144, 151, 182, 197]

s.loop(256030, (309364 - 256030)/(beat * 16))
for i in range(16):
j = (i+1)%16
s.color(0, i*beat, (i+1)*beat, rs[i], gs[i], bs[i], rs[j], gs[j], bs[j], True)


def barEffect(numBars, xOffset, xDist, width, minHeight, heightRange, heightPeriod, heightOffset, alpha, bottom = True):
for i in range(numBars):
#print(i)

anchor = "BottomCentre" if bottom else "TopCentre"
squareType = "sb/bottom_square.png" if bottom else "sb/top_square.png"
yPos = 440 + heightOffset if bottom else 40 - heightOffset
angle = -pi/6 if bottom else pi/6

squareA = osbject(squareType, "Background", anchor, 320 - xOffset, yPos)
squareB = osbject(squareType, "Background", anchor, 320 + xOffset, yPos)

squareA.para(0, 21364, 309364, "A")
squareB.para(0, 21364, 309364, "A")

squareA.loop(21364, (309364-21364)//120000 + 1)
squareA.rotate(16, 0, 30000, angle, 0, True)
squareA.rotate(15, 30000, 60000, 0, -angle, True)
squareA.rotate(16, 60000, 90000, -angle, 0, True)
squareA.rotate(15, 90000, 120000, 0, angle, True)

squareB.loop(21364, (309364-21364)//120000 + 1)
squareB.rotate(16, 0, 30000, -angle, 0, True)
squareB.rotate(15, 30000, 60000, 0, angle, True)
squareB.rotate(16, 60000, 90000, angle, 0, True)
squareB.rotate(15, 90000, 120000, 0, -angle, True)

squareA.loop(21364 + i * beat, int((309364-21364)/(beat * numBars)))
squareA.fade(0, 0, beat, 0, alpha, True)
squareA.fade(0, beat * numBars - beat//2, beat * numBars, alpha, 0, True)
squareA.moveX(1, 0, beat * numBars, 320 - xOffset, 320 - xOffset - xDist, True)


squareB.loop(21364 + i * beat, int((309364-21364)/(beat * numBars)))
squareB.fade(0, 0, beat, 0, alpha, True)
squareB.fade(0, beat * numBars - beat//2, beat * numBars, alpha, 0, True)
squareB.moveX(1, 0, beat * numBars, 320 + xOffset, 320 + xOffset + xDist, True)

backgroundColor(squareA, True)
backgroundColor(squareB, True)

squareA.loop(21364 + i * beat, (309364-21364)//(beat * heightPeriod))
squareA.vecscale(17, 0, heightPeriod * beat // 2, width, minHeight, width, minHeight + heightRange, True)
squareA.vecscale(17, heightPeriod * beat // 2, heightPeriod * beat, width, minHeight + heightRange, width, minHeight , True)

squareB.loop(21364 + i * beat, (309364-21364)//(beat * heightPeriod))
squareB.vecscale(17, 0, heightPeriod * beat // 2, width, minHeight, width, minHeight + heightRange, True)
squareB.vecscale(17, heightPeriod * beat // 2, heightPeriod * beat, width, minHeight + heightRange, width, minHeight , True)


''' Spectrum disabled because too laggy
lastHeight = (spectrum[i][0]-spec_min)/(spec_max - spec_min)*heightRange + minHeight
lastHeight = math.ceil(lastHeight * 1000)/1000;

lastTime = int(round(spec_t[0]*1000))

for index, power in enumerate(spectrum[i]):
power = (power-spec_min)/(spec_max-spec_min)*heightRange + minHeight
power = math.ceil(power*1000)/1000

if power == lastHeight or int(round(spec_t[index]*1000)) < 21364 or int(round(spec_t[index]*1000)) > 309364 or index % 2 is not 0:
lastTime = int(round(spec_t[index]*1000))
continue
else:
squareA.vecscale(2, lastTime, int(round(spec_t[index]*1000)), width, lastHeight, width, power)
squareB.vecscale(2, lastTime, int(round(spec_t[index]*1000)), width, lastHeight, width, power)

'''

barEffect(4, 0, 600, 1.4, 2, 3, 4, 30, 0.9)
barEffect(4, 0, 600, 1.4, 2, 3, 4, 30, 0.9, False)

barEffect(6, -20, 600, 1, 3, 2.5, 3, 10, 0.7)
barEffect(6, -20, 600, 1, 3, 2.5, 3, 10, 0.7, False)

barEffect(6, -40, 500, 0.8, 4, 2, 2, -10, 0.5)
barEffect(6, -40, 500, 0.8, 4, 2, 2, -10, 0.5, False)

barEffect(10, -60, 500, 0.5, 5, 1, 5, -30, 0.3)
barEffect(10, -60, 500, 0.5, 5, 1, 5, -30, 0.3, False)

''' Sound wave effect (disabled because too laggy)
stepsize = 33

waveEffect = []

for i in range(20):
square = osbject("sb/white_square_small.png", "Foreground", "CentreLeft", i * 32, 240)

square.loop(21364, int((309364-21364)/(beat * 3)));
square.color(17, 0, beat, 0, 0, 255, 255, 0, 0, True);
square.color(17, beat, 2*beat, 255, 0, 0, 0, 255, 0, True);
square.color(17, 2*beat, 3*beat, 0, 255, 0, 0, 0, 255, True);

waveEffect.append(square)


for ms in range(21364, 309364, stepsize):
print(ms)
for i in range(20):
thisSampleId = int((ms + 2 * i) * 44.1)
nextSampleId = int((ms + 2 * (i + 1)) * 44.1)

thisSampleNormalized = music[thisSampleId, 0] / 32767
nextSampleNormalized = music[nextSampleId, 0] / 32767

thisSample = 240 + (thisSampleNormalized) * 80
nextSample = 240 + (nextSampleNormalized) * 80

dy = nextSample - thisSample
dx = 32

length = sqrt(dx * dx + dy * dy)

angle = atan2(dy, dx)

waveEffect[i].moveY(0, ms, ms + stepsize, int(thisSample), int(thisSample))
waveEffect[i].vecscale(0, ms, ms + stepsize, length, 1, length, 1)
waveEffect[i].rotate(0, ms, ms + stepsize, angle, angle)

'''

back_white = osbject("sb/white.png", "Background", "Centre", 320, 240)
back_white.fade(0, 20030, 21364, 0, 1)
back_white.fade(0, 21364, 21364 + beat//4, 1, 0)
back_white.fade(0, 254697, 256030, 0, 1)
back_white.fade(0, 256030, 256030 + beat//4, 1, 0)

rainbow_r = [255, 255, 255, 255, 255, 255, 255, 154, 23, 0, 0, 0, 0, 0, 0, 0]
rainbow_g = [51, 87, 126, 165, 201, 232, 254, 255, 255, 255, 255, 224, 166, 101, 41, 0]
rainbow_b = [0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 239, 255, 255, 255, 255, 255]

trailLength = 16
for i in range(trailLength):
effect = osbject("sb/asriel_full", "Background", "Centre", 320, 215)
effect.fade(0, 21364, 309364, 1 - i/trailLength, 1 - i/trailLength)
effect.color(0, 21364, 309364, rainbow_r[i%16], rainbow_g[i%16], rainbow_b[i%16], rainbow_r[i%16], rainbow_g[i%16], rainbow_b[i%16])
regularMovement(effect, 0, -25, scaleY = 1, delay = i * beat // 16)

for i in range(trailLength//2):
effect = osbject("sb/asriel_full", "Background", "Centre", 320, 215)
idx = (2*i) % 16
effect.color(0, 21364, 309364, rainbow_r[idx], rainbow_g[idx], rainbow_b[idx], rainbow_r[idx], rainbow_g[idx], rainbow_b[idx])
regularMovement(effect, 0, -25, scaleY = 1, delay = 2*i * beat // 16)
effect.para(0, 21364, 309364, "A")
flash(effect, alpha = 1 - 2*i/trailLength)

bodyOffsetX = 0

armOffsetX = 44
armOffsetY = -18

cape2OffsetX = 44
cape2OffsetY = -68

capeOffsetY = -78

headOffsetY = -104

necklaceOffsetY = -64

feetOffsetX = 4
feetOffsetY = 72

feet = osbject("sb/feet.png", "Background", "Centre", 320 + feetOffsetX, 240 + feetOffsetY)
body = osbject("sb/body.png", "Background", "Centre", 320 + bodyOffsetX, 240)
armL = osbject("sb/armL.png", "Background", "Centre", 320 + armOffsetX, 240 + armOffsetY)
armR = osbject("sb/armR.png", "Background", "Centre", 320 - armOffsetX, 240 + armOffsetY)
cape2L = osbject("sb/cape2L.png", "Background", "Centre", 320 + cape2OffsetX, 240 + cape2OffsetY)
cape2R = osbject("sb/cape2R.png", "Background", "Centre", 320 - cape2OffsetX, 240 + cape2OffsetY)
cape = osbject("sb/cape.png", "Background", "Centre", 320, 240 + capeOffsetY)
necklace = osbject("sb/necklace.png", "Background", "Centre", 320, 240 + necklaceOffsetY)
head = osbject("sb/head.png", "Pass", "Centre", 320, 240 + headOffsetY)
head_disappoint = osbject("sb/disappoint.png", "Fail", "Centre", 320, 240 + headOffsetY, framecount = 4, framerate = 250, loop = "LoopForever")


introMovement(body)
introMovement(armL, armOffsetY)
introMovement(armR, armOffsetY)
introMovement(cape2L, cape2OffsetY)
introMovement(cape2R, cape2OffsetY)
introMovement(cape, capeOffsetY)
introMovement(head, headOffsetY)
introMovement(head_disappoint, headOffsetY)
introMovement(necklace, necklaceOffsetY)
introMovement(feet, feetOffsetY)

regularMovement(body, bodyOffsetX, 0, delay = 12)
regularMovement(armL, armOffsetX, armOffsetY, 1.04)
regularMovement(armR, -armOffsetX, armOffsetY, 1.04)
regularMovement(cape2L, cape2OffsetX, cape2OffsetY, 1.01)
regularMovement(cape2R, -cape2OffsetX, cape2OffsetY, 1.01)
regularMovement(cape, 0, capeOffsetY, 1.01)
regularMovement(head_disappoint, 0, headOffsetY, 1.05)
regularMovement(head, 0, headOffsetY, 1.05)
regularMovement(necklace, 0, necklaceOffsetY, 1.02)
regularMovement(feet, feetOffsetX, feetOffsetY, 0.97)

bottomLight = osbject("sb/white_square_gradient.png", "Foreground", "BottomCentre", 320, 480);
bottomLight.para(0, 21364, 309364, "A")
bottomLight.vecscale(0, 21364, 309364, 30, 6, 30, 6);

topLight = osbject("sb/white_square_gradient.png", "Foreground", "TopCentre", 320, 0);
topLight.para(0, 21364, 309364, "A")
topLight.para(0, 21364, 309364, "V")
topLight.vecscale(0, 21364, 309364, 30, 6, 30, 6);

backgroundColor(bottomLight)
backgroundColor(topLight)

flash(bottomLight)
flash(topLight)

undertale = osbject("undertale.png", "Foreground", "Centre", 320, 240)
undertale.fade(0, 0, start + beat, 1, 0)

black = osbject("sb/black.png", "Foreground", "Centre", 320, 240)
black.fade(0, 309030, 309364, 0, 1)
black.fade(0, 309364, 314697, 1, 1)

# output .osu file
path = "redacted"
osbject.end(path)

osbpy.py
from random import randint
import os
import pylab as plt
import math
import numpy as np
from scipy.io import wavfile

layers = ["Background","Fail","Pass","Foreground"]
origins = ["TopLeft","TopCentre","TopRight","CentreLeft","Centre","CentreRight","BottomLeft","BottomCentre","BottomRight"]
spect = []

def sinus(har, radius, sinheight):
x1 = np.linspace(0, sinheight, har)
y1 = np.sin(x1)
sinus = plt.plot(x1, y1, 'bo')
ysinus = sinus[0].get_ydata()*radius
return ysinus

def gencircle(r, n):
for i in range(len(r)):
for j in range(n[i]):
yield r[i], j*(2 * np.pi / n[i])

def circle(har, radius):
circle = []
xcircle = {}
ycircle = {}
for r, t in gencircle([2*radius], [har]):
circle += plt.plot(r * np.cos(t), r * np.sin(t), 'bo')
for index, val in enumerate(circle):
xcircle[index] = val.get_xdata()
ycircle[index] = val.get_ydata()
return ycircle, xcircle

def check_easing(es):
if es not in range(35):
return True
else:
return False

class osbject:
back_obj = []
fail_obj = []
pass_obj = []
fore_obj = []
obj_layers = {"Background" : back_obj, "Fail" : fail_obj, "Pass" : pass_obj, "Foreground" : fore_obj}

def __init__(self, path, layer, origin, posX, posY, framecount=None, framerate=None, loop=None):
osbject.obj_layers[layer].append(self)
valid = True
errors = []
self.props = []

if type(path) is not str:
errors.append("Invalid Path! ")
valid = False
if layer not in layers:
errors.append("Invalid Layer! ")
valid = False
if origin not in origins:
errors.append("Invalid Origin! ")
valid = False
try:
posX = int(posX)
posY = int(posY)
except:
errors.append("Invalid Position! ")
valid = False
if framecount is not None and framerate is not None and loop is not None:
if not isinstance(framecount, int) or not isinstance(framerate, int):
errors.append("Invalid Frame count or Frame rate! ")
valid = False
if loop not in ["LoopForever","LoopOnce"]:
errors.append("Invalid Type! ")
valid = False
if valid:
self.props.append("Animation,%s,%s,%s,%s,%s,%s,%s,%s" % (layer, origin, path, posX, posY, framecount, framerate, loop))
else:
self.props = errors
else:
if valid:
self.props.append("Sprite,%s,%s,\"%s\",%s,%s" % (layer, origin, path, posX, posY))
else:
self.props = errors

def fade(self, easing,startTime,endTime,startFade,endFade,loop = False):
valid = True
errors = ""
if check_easing(easing):
errors.append("Invalid Easing! ")
valid = False
try:
startTime = int(startTime)
endTime = int(endTime)
except:
errors.append("Invalid Time! ")
valid = False
try:
startFade = float(startFade)
endFade = float(endFade)
except:
errors.append("Invalid Fade! ")
valid = False
if valid:
if loop:
self.props.append("\n F,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startFade, endFade))
else:
self.props.append("\n F,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startFade, endFade))
else:
self.props.append("\n" + "".join(errors))

def move(self, easing,startTime,endTime,startmoveX,startmoveY,endmoveX,endmoveY,loop = False):
valid = True
errors = ""
if check_easing(easing):
errors.append("Invalid Easing! ")
valid = False
try:
startTime = int(startTime)
endTime = int(endTime)
except:
errors.append("Invalid Time! ")
valid = False
if not isinstance(startmoveX, int) or not isinstance(startmoveY, int) or not isinstance(endmoveX, int) or not isinstance(endmoveY, int):
errors.append("Invalid Move! ")
valid = False
if valid:
if loop:
self.props.append("\n M,%s,%s,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startmoveX, startmoveY, endmoveX, endmoveY))
else:
self.props.append("\n M,%s,%s,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startmoveX, startmoveY, endmoveX, endmoveY))
else:
self.props.append("\n" + "".join(errors))

def moveX(self, easing,startTime,endTime,startmoveX,endmoveX,loop = False):
valid = True
errors = ""
if check_easing(easing):
errors.append("Invalid Easing! ")
valid = False
try:
startTime = int(startTime)
endTime = int(endTime)
startmoveX = int(startmoveX)
endmoveX = int(endmoveX)
except:
errors.append("Invalid Arguments! ")
valid = False
if valid:
if loop:
self.props.append("\n MX,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startmoveX, endmoveX))
else:
self.props.append("\n MX,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startmoveX, endmoveX))
else:
self.props.append("\n" + "".join(errors))

def moveY(self, easing,startTime,endTime,startmoveY,endmoveY,loop = False):
valid = True
errors = ""
if check_easing(easing):
errors.append("Invalid Easing! ")
valid = False
try:
startTime = int(startTime)
endTime = int(endTime)
startmoveY = int(startmoveY)
endmoveY = int(endmoveY)
except:
errors.append("Invalid Arguments! ")
valid = False
if valid:
if loop:
self.props.append("\n MY,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startmoveY, endmoveY))
else:
self.props.append("\n MY,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startmoveY, endmoveY))
else:
self.props.append("\n" + "".join(errors))

def scale(self, easing,startTime,endTime,startScale,endScale,loop = False):
valid = True
errors = ""
if check_easing(easing):
errors.append("Invalid Easing! ")
valid = False
try:
startTime = int(startTime)
endTime = int(endTime)
startScale = float(startScale)
endScale = float(endScale)
except:
errors.append("Invalid Arguments! ")
valid = False
if valid:
if loop:
self.props.append("\n S,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startScale, endScale))
else:
self.props.append("\n S,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startScale, endScale))
else:
self.props.append("\n" + "".join(errors))

def vecscale(self, easing,startTime,endTime,startscaleX,startscaleY,endscaleX,endscaleY,loop = False):
valid = True
errors = ""
if check_easing(easing):
errors.append("Invalid Easing! ")
valid = False
if check_easing(easing):
errors.append("Invalid Easing! ")
valid = False
try:
startTime = int(startTime)
endTime = int(endTime)
startscaleX = float(startscaleX)
endscaleX = float(endscaleX)
startscaleY = float(startscaleY)
endscaleY = float(endscaleY)
except:
errors.append("Invalid Arguments! ")
valid = False
if valid:
if loop:
self.props.append("\n V,%s,%s,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startscaleX, startscaleY, endscaleX, endscaleY))
else:
self.props.append("\n V,%s,%s,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startscaleX, startscaleY, endscaleX, endscaleY))
else:
self.props.append("\n" + "".join(errors))

def rotate(self, easing,startTime,endTime,startRotate,endRotate,loop = False):
valid = True
errors = ""
if check_easing(easing):
errors.append("Invalid Easing! ")
valid = False
try:
startTime = int(startTime)
endTime = int(endTime)
startRotate = float(startRotate)
endRotate = float(endRotate)
except:
errors.append("Invalid Arguments! ")
valid = False
if valid:
if loop:
self.props.append("\n R,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startRotate, endRotate))
else:
self.props.append("\n R,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startRotate, endRotate))
else:
self.props.append("\n" + "".join(errors))

def color(self, easing,startTime,endTime,startR,startG,startB,endR,endG,endB,loop = False):
valid = True
errors = ""
if check_easing(easing):
errors.append("Invalid Easing! ")
valid = False
try:
startTime = int(startTime)
endTime = int(endTime)
startR = int(startR)
startG = int(startG)
startB = int(startB)
endR = int(endR)
endG = int(endG)
endB = int(endB)
except:
errors.append("Invalid Arguments! ")
valid = False
if valid:
if loop:
self.props.append("\n C,%s,%s,%s,%s,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startR, startG, startB, endR, endG, endB))
else:
self.props.append("\n C,%s,%s,%s,%s,%s,%s,%s,%s,%s" % (easing, startTime, endTime, startR, startG, startB, endR, endG, endB))
else:
self.props.append("\n" + "".join(errors))

def para(self, easing,startTime,endTime,parameter):
valid = True
errors = ""
if check_easing(easing):
errors.append("Invalid Easing! ")
valid = False
try:
startTime = int(startTime)
endTime = int(endTime)
except:
errors.append("Invalid Arguments! ")
valid = False
if parameter not in ["H", "V", "A"]:
errors.append("Invalid Parameter!")
valid = False
if valid:
self.props.append("\n P,%s,%s,%s,%s" % (easing, startTime, endTime, parameter))
else:
self.props.append("\n" + "".join(errors))

def loop(self, startTime,loopCount):
valid = True
errors = ""
try:
startTime = int(startTime)
loopCount = int(loopCount)
except:
errors.append("Invalid Arguments! ")
valid = False
if valid:
self.props.append("\n L,%s,%s" % (startTime, loopCount))
else:
self.props.append("\n" + "".join(errors))

def trigger(self, trigger, startTime, endTime):
valid = True
errors = ""
if type(trigger) is not str:
errors.append("Invalid Trigger!")
valid = False
try:
startTime = int(startTime)
endTime = int(endTime)
except:
errors.append("Invalid Arguments! ")
valid = False
if valid:
self.props.append("\n T,%s,%s,%s" % (trigger,startTime, endTime))
else:
self.props.append("\n" + "".join(errors))

@classmethod
def end(cl,osbfile):
if os.path.isfile(osbfile):
os.remove(osbfile)
with open(osbfile, "a") as text:
text.write("[Events]\n//Background and Video events\n//Storyboard Layer 0 (Background)\n")

for val in cl.back_obj:
text.write("%s\n" % "".join(val.props))

text.write("//Storyboard Layer 1 (Fail)\n")
for val in cl.fail_obj:
text.write("%s\n" % "".join(val.props))

text.write("//Storyboard Layer 2 (Pass)\n")
for val in cl.pass_obj:
text.write("%s\n" % "".join(val.props))

text.write("//Storyboard Layer 3 (Foreground)\n")
for val in cl.fore_obj:
text.write("%s\n" % "".join(val.props))

text.write("//Storyboard Sound Samples")

def spectrum(wav_file,mi,mx,har,start,end,posX,posY,layer,origin,gap=0,arrange="",radius=30,sinheight=6.1):
frame_rate, snd = wavfile.read(wav_file)
sound_info = snd[:,0]
spectrum, freqs, t, im = plt.specgram(sound_info,NFFT=1024,Fs=frame_rate,noverlap=5,mode='magnitude')
n = 0
rotation = 6.2831
sinpos = {}
cirpos = {}
if arrange is "sinus":
sinpos = sinus(har,radius,sinheight)
for i in range(har):
cirpos[i] = 0
elif arrange is "circle":
gap = 0
sinpos, cirpos = circle(har,radius)
rotation /= har
else:
for i in range(har):
sinpos[i] = 0
for i in range(har):
cirpos[i] = 0
maximum = plt.amax(spectrum)
minimum = plt.amin(spectrum)
position = 0
while n < har:
lastval = ((spectrum[n][0]-minimum)/(maximum - minimum))*(mx-mi)+mi
lastval = math.ceil(lastval*1000)/1000
lasttime = int(round(t[0]*1000))
spect.append(osbject("bar.png",layer,origin,posX+position*gap+int(round(float(cirpos[n]))),posY+int(round(float(sinpos[n])))))
position += 1
if arrange is "circle":
spect[n].rotate(0,start,start,math.ceil((1.5707+n*rotation)*1000)/1000,math.ceil((1.5707+n*rotation)*1000)/1000)
for index,power in enumerate(spectrum[n]):
power = ((power-minimum)/(maximum - minimum))*(mx-mi)+mi
power = math.ceil(power*1000)/1000
if power == lastval or int(round(t[index]*1000)) < start or int(round(t[index]*1000)) > end or index % 2 is not 0:
lasttime = int(round(t[index]*1000))
continue
else:
spect[n].vecscale(0,lasttime,int(round(t[index]*1000)),1,lastval,1,power)
lastval = power
lasttime = int(round(t[index]*1000))
n += 1
Kryptogram
That SB though! Nice work!
Phos-
Hey, m4m from your queue!

[General]
  1. Your offset is a bit late; an offset of 13 would work much better. Once you do this remember to resnap all notes and go through the beatmap carefully.
  2. Your audio bitrate is 255kbps, which is above the maximum allowed quality which is 192kbps. This restriction is in place to keep the filesize low and to allow players with poor sound cards to enjoy the map. I decoded it to 192kpbs for you, which you can find here.
  3. You are not using a 0 byte wav file! The ranking criteria states that all hitsounds need to be at least 100ms long with the exception of silent hitsounds, which have to be 0 bytes. You can download one from either the ranking criteria directly, or from here
  4. Your map has zero spinners, which is bad because it'll stagnate the leaderboard when your map gets ranked. I suggest having one at 05:09:447 - because there is an adequate fade-out that would justify a spinner, along with a long constant sound that would make a spinner even more fitting.
  5. Come up with a more creative difficulty name than "marathon"? You have more room to be creative with marathons than you do with spreads, so take advantage of it~
[Marathon]
  1. 00:30:697 (5,6,7,8) - I'm not too fond of this pattern. It flows awkwardly and the overlaps makes it seem really cramped. You should space it out a bit.
  2. 00:32:030 (1) - Why does this end 1/4 early? This creates an awkward gap, since the beat at 00:32:364 isn't being stressed in any way at all. Extending the slider by 1/4 should solve this problem.
  3. 00:34:030 (8,9) - Replace these with four hitcircles? The beats they land on are quite individualised, so having to tap on four notes rather than two would help express that. Same applies to 00:36:696 (8,9) - and 00:39:364 (8,9) - .
  4. 00:52:864 - Why isn't the 1/2 here mapped? Since this is a 6* marathon, it would be awkward to leave this empty, and the 1/1 monotony can get old after a while.
  5. 01:07:697 (3,4) - Minor, but could you get rid of the slight overlap? It's quite noticeable so I think the pattern would seem neater if you changed this.
  6. 01:17:364 (1,2) - Increase the spacing here to make the 1/1 gap more noticeable. With the speed players are going at, people are likely to mistake this for a 1/2 and sliderbreak. Same applies to many other 1/1 gaps you have in this section, such as 01:22:697 (1,2) - , 01:28:031 (1,2) - , etc.
  7. 01:19:697 (4,5) - Why is the jump here so big? Nothing in the music really suggests this and it can be very hard to read due to the abundance of 1/1. It is more than likely that a player is to misread for a 1/1 too.
  8. 01:44:697 (3,4,5) - This really doesn't work at a 180° angle, as the emphasis going to (5) feels so tacky. You need to make it much sharper, like you did with 01:39:364 (3,4,5) - .
  9. 02:22:530 (4) - I would change this slider so that the head of it doesn't overlap with the trail. This would look a bit more polished imo.
  10. 02:29:030 (7,1) - Swap these two NCs. This way the player can easily know when they have to start moving and they won't break from hitting (1) too late.
  11. 02:36:197 (2,3,4,5,6,7,8) - Why is there such a sudden spike in jump intensity? Nothing in the music suggests this so it can feel quite jarring to play. I recommend you tone it down a bit.
  12. 02:45:364 (1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8) - Like the above suggestion, but this is even worse. Why do you have such huge jumps? The 1/2 ticks aren't stressed much at all and you're just mapping these to a drum pattern that hasn't really increased much in intensity. This can be very tacky, so I highly recommend toning this down a bit.
  13. 02:57:364 (3,4,5,6,7) - Make these angles sharper to be consistent with the rest of the section as of now.
  14. 03:17:697 (2,3,4) - These angles could also be a bit sharper to put more emphasis on the notes at this point.
  15. 03:42:697 (1,2,3,4,5,6,7,8) - Again, the difficulty here is way over the top. Sure the synth might have gotten a bit louder, but there isn't any specific stress going to the 1/2 that you put jumps on, making them unsuitable. Tone it down a bit, please.
  16. 03:53:196 (6,1) - The (1) definitely needs more emphasis. It is on such an obuse angle with such low spacing that it feels really tacky. I would space the two notes out much more.
  17. 04:10:697 (1,1) - I'm sure that these sliders are unrankable, as the ranking criteria states that Every slider must have a clear and visible path to follow from start to end. In the case of these sliders, the overlaps make them so ambiguous that I wouldn't be sure where to go. Same applies for 04:58:697 (1) - . Please make sure your sliders are clear!
  18. 04:19:197 (3,4,5) - This is an awkward angle for such a large spacing change. I'd make it more acute because that way your giving proper emphasis to the change in the song.
  19. 04:25:197 (5,1,2) - What's up with the rhythm here? I see that your trying to emphasise the 1/4 before (2) but the player has no way of knowing this so they're likely to hit (1) way too early. There's also the fact that the downbeat is straight out skipped, which is bad. I would just move (1) 1/4 back so it's on the downbeat. This would get rid of the awkward gap. Same applies for 04:36:114 (1,2) - too.
  20. 04:46:197 (5) - Why did you choose to map this synth as a single hitcircle? This is unfitting as it leaves an awkward gap where the player is likely to hit (1) too early since the spacing is the same. I would just make (5) a 1/2 slider, as that would give the synth proper emphasis and that would go with the song.
  21. 04:52:697 (1,2,3,4) - With a higher pitch, notes should be more acute and emphasised, not the opposite. I recommend you space these out much more and utilise sharper angles here.
  22. 04:53:364 (1,2,3,4,1,2,3) - Compared to the rest of the pattern, these can be very awkward to read, and nothing in the song suggests such a major style change. I recommend you make this a normal jump pattern like what you've been doing before.
Personally, I think this map needs a bit of work. Focus on improving your rhythms and patterns and the beatmap will begin to improve. Good luck!
Topic Starter
Flowey

-Faded- wrote:

Hey, m4m from your queue!

[General]
  1. Your offset is a bit late; an offset of 13 would work much better. Once you do this remember to resnap all notes and go through the beatmap carefully. I tried 13 and it seemed too early. I changed the offset to 73 which seems correct now.
  2. Your audio bitrate is 255kbps, which is above the maximum allowed quality which is 192kbps. This restriction is in place to keep the filesize low and to allow players with poor sound cards to enjoy the map. I decoded it to 192kpbs for you, which you can find here. Thanks!
  3. You are not using a 0 byte wav file! The ranking criteria states that all hitsounds need to be at least 100ms long with the exception of silent hitsounds, which have to be 0 bytes. You can download one from either the ranking criteria directly, or from here Thanks!
  4. Your map has zero spinners, which is bad because it'll stagnate the leaderboard when your map gets ranked. I suggest having one at 05:09:447 - because there is an adequate fade-out that would justify a spinner, along with a long constant sound that would make a spinner even more fitting. Done
  5. Come up with a more creative difficulty name than "marathon"? You have more room to be creative with marathons than you do with spreads, so take advantage of it~ Changed. (Marathon was a placeholder.)
[Marathon]
  1. 00:30:697 (5,6,7,8) - I'm not too fond of this pattern. It flows awkwardly and the overlaps makes it seem really cramped. You should space it out a bit. Changed.
  2. 00:32:030 (1) - Why does this end 1/4 early? This creates an awkward gap, since the beat at 00:32:364 isn't being stressed in any way at all. Extending the slider by 1/4 should solve this problem. Oops. Fixed
  3. 00:34:030 (8,9) - Replace these with four hitcircles? The beats they land on are quite individualised, so having to tap on four notes rather than two would help express that. Same applies to 00:36:696 (8,9) - and 00:39:364 (8,9) - . Done.
  4. 00:52:864 - Why isn't the 1/2 here mapped? Since this is a 6* marathon, it would be awkward to leave this empty, and the 1/1 monotony can get old after a while. Ok, added.
  5. 01:07:697 (3,4) - Minor, but could you get rid of the slight overlap? It's quite noticeable so I think the pattern would seem neater if you changed this. Fixed.
  6. 01:17:364 (1,2) - Increase the spacing here to make the 1/1 gap more noticeable. With the speed players are going at, people are likely to mistake this for a 1/2 and sliderbreak. Same applies to many other 1/1 gaps you have in this section, such as 01:22:697 (1,2) - , 01:28:031 (1,2) - , etc. Done.
  7. 01:19:697 (4,5) - Why is the jump here so big? Nothing in the music really suggests this and it can be very hard to read due to the abundance of 1/1. It is more than likely that a player is to misread for a 1/1 too. Made jump smaller.
  8. 01:44:697 (3,4,5) - This really doesn't work at a 180° angle, as the emphasis going to (5) feels so tacky. You need to make it much sharper, like you did with 01:39:364 (3,4,5) - . Done.
  9. 02:22:530 (4) - I would change this slider so that the head of it doesn't overlap with the trail. This would look a bit more polished imo. Done
  10. 02:29:030 (7,1) - Swap these two NCs. This way the player can easily know when they have to start moving and they won't break from hitting (1) too late. Done.
  11. 02:36:197 (2,3,4,5,6,7,8) - Why is there such a sudden spike in jump intensity? Nothing in the music suggests this so it can feel quite jarring to play. I recommend you tone it down a bit. Moved things closer.
  12. 02:45:364 (1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8) - Like the above suggestion, but this is even worse. Why do you have such huge jumps? The 1/2 ticks aren't stressed much at all and you're just mapping these to a drum pattern that hasn't really increased much in intensity. This can be very tacky, so I highly recommend toning this down a bit. Moved things closer. At the time, it seemed like a good idea.
  13. 02:57:364 (3,4,5,6,7) - Make these angles sharper to be consistent with the rest of the section as of now. Done.
  14. 03:17:697 (2,3,4) - These angles could also be a bit sharper to put more emphasis on the notes at this point. Done.
  15. 03:42:697 (1,2,3,4,5,6,7,8) - Again, the difficulty here is way over the top. Sure the synth might have gotten a bit louder, but there isn't any specific stress going to the 1/2 that you put jumps on, making them unsuitable. Tone it down a bit, please. Done.
  16. 03:53:196 (6,1) - The (1) definitely needs more emphasis. It is on such an obuse angle with such low spacing that it feels really tacky. I would space the two notes out much more. Done.
  17. 04:10:697 (1,1) - I'm sure that these sliders are unrankable, as the ranking criteria states that Every slider must have a clear and visible path to follow from start to end. In the case of these sliders, the overlaps make them so ambiguous that I wouldn't be sure where to go. Same applies for 04:58:697 (1) - . Please make sure your sliders are clear! Made them less confusing.
  18. 04:19:197 (3,4,5) - This is an awkward angle for such a large spacing change. I'd make it more acute because that way your giving proper emphasis to the change in the song. Done.
  19. 04:25:197 (5,1,2) - What's up with the rhythm here? I see that your trying to emphasise the 1/4 before (2) but the player has no way of knowing this so they're likely to hit (1) way too early. There's also the fact that the downbeat is straight out skipped, which is bad. I would just move (1) 1/4 back so it's on the downbeat. This would get rid of the awkward gap. Same applies for 04:36:114 (1,2) - too. Oops. Fixed.
  20. 04:46:197 (5) - Why did you choose to map this synth as a single hitcircle? This is unfitting as it leaves an awkward gap where the player is likely to hit (1) too early since the spacing is the same. I would just make (5) a 1/2 slider, as that would give the synth proper emphasis and that would go with the song. I added a hit circle instead.
  21. 04:52:697 (1,2,3,4) - With a higher pitch, notes should be more acute and emphasised, not the opposite. I recommend you space these out much more and utilise sharper angles here. Done.
  22. 04:53:364 (1,2,3,4,1,2,3) - Compared to the rest of the pattern, these can be very awkward to read, and nothing in the song suggests such a major style change. I recommend you make this a normal jump pattern like what you've been doing before. Removed the stacking.
Personally, I think this map needs a bit of work. Focus on improving your rhythms and patterns and the beatmap will begin to improve. Good luck!
Thanks for the mod! It was super helpful! :)
BanchoBot
This modding thread has been migrated to the new "modding discussions" system. Please make sure to re-post any existing (and unresolved) efforts to the new system as required.
Please sign in to reply.

New reply