mirror of
https://gitlab.com/GameFeverOnline/py-mmlv.git
synced 2025-12-18 09:47:41 -04:00
229 lines
9.1 KiB
Python
229 lines
9.1 KiB
Python
# A Mega Man Maker MMLV Library/Module By Timothy J. (GameFeverOnline, www.youtube.com/@GameFeverOnline)
|
|
"""
|
|
The goal is to create a library that reads a mmlv file, and then creates variables for each object, tile, background, etc... So that you could on another program import this as a module
|
|
and just give it for example, mm1iceman = [1, 2, 3] , the 1 meaning that it's active and the 2 and 3 it's position in space. In the future there will be more inputs for settings of objects.
|
|
It could also work by calling a function, say place_tile(tilename, x, y) and then do that for every tile placement call. That would separate the placing of tiles from the placing of objects and more.
|
|
"""
|
|
|
|
try:
|
|
import configparser, os, definitions
|
|
import requests
|
|
except ModuleNotFoundError:
|
|
print("module not found, please install configparser, requests, os and have the definitions.py in the same folder as mmlv_library.py")
|
|
section = "Level"
|
|
config = configparser.ConfigParser()
|
|
#filename = "blank.mmlv"
|
|
#config.read(filename) #this must be changed to support writing ONLY the changes when giving and argument in write_changes(), and not filename PLUS the changes. Todo: Enable Modifying of levels, not just creating.
|
|
alias = definitions.aliases
|
|
supported_values = definitions.supported_values
|
|
max_x = 799
|
|
max_y = 279
|
|
max_room_x = 49
|
|
max_room_y = 19
|
|
|
|
# converts from multiples of 16 to normal x and y values. for use in reading
|
|
def conv_coordinates(x16, y16):
|
|
if x16 < 1 or y16 < 1:
|
|
x = x16 / 16
|
|
y = y16 / 16
|
|
else:
|
|
x = 0
|
|
y = 0
|
|
return [x, y]
|
|
|
|
#done. converts from normal x and y values to multiples of 16. for use in writing
|
|
def conv_coordinates_x16(x, y):
|
|
x16 = x * 16
|
|
y16 = y * 16
|
|
return [x16, y16]
|
|
|
|
#adds apostrofes to the string
|
|
def set_apos(object):
|
|
apos = '"'+ str(object) + '"'
|
|
return apos
|
|
|
|
#done. writes the changes to file specified in global variable filename.
|
|
def read_file(filename="blank.mmlv"):
|
|
config.read(filename)
|
|
|
|
def write_changes(filename="blank.mmlv"):
|
|
#Well well well... this for loop is here to make every thing work. I'm not sure for what the 1s, 1q,1r and 1p keys are, but if they are the same as a blank mmlv created by mmm, it just doesn't work. It's weird.'
|
|
for letter in "srqp":
|
|
if letter == "q":
|
|
config.set(section,"1"+letter, set_apos(12800) )
|
|
elif letter == "s":
|
|
config.set(section,"1"+letter, set_apos(4480) )
|
|
else:
|
|
config.set(section,"1"+letter, set_apos(0) )
|
|
with open(filename, 'w') as configfile:
|
|
config.write(configfile, space_around_delimiters=False)
|
|
|
|
#done. returns what is available in the file. without values. So far unneeded
|
|
def get_options():
|
|
options = config.options(section)
|
|
return options
|
|
|
|
#so far unneeded
|
|
def get_items():
|
|
items = config.items(section)
|
|
return items
|
|
|
|
|
|
def set_setting(alias_or_code,value,code=False):
|
|
if not code:
|
|
alias_or_code = alias[alias_or_code]
|
|
|
|
else:
|
|
alias_or_code = str(alias_or_code)
|
|
value = set_apos(value)
|
|
config.set(section, alias_or_code, value)
|
|
|
|
#done. Sets level creator's user name
|
|
def set_user(username):
|
|
if config.has_option(section, alias["user_name"]):
|
|
username = '"' + str(username) + '"'
|
|
config.set(section, alias["user_name"],username.lower())
|
|
#done. Not tested
|
|
def get_user():
|
|
if config.has_option(section, alias["user_name"]):
|
|
current_username = config.get(section, alias["user_name"])
|
|
return current_username
|
|
|
|
|
|
def is_block_used(x, y, details=False):
|
|
conv_list = conv_coordinates_x16(x, y)
|
|
x = conv_list[0]
|
|
y = conv_list[1]
|
|
for letter in definitions.block_with_coordinates:
|
|
current = letter + str(x) + "," + str(y)
|
|
try:
|
|
answ_option = config[section][current]
|
|
return True
|
|
except KeyError:
|
|
return False
|
|
#this will optionally report WHAT is actually in there.
|
|
|
|
def set_tile_value(k_value, j_value, i_value, e_value, a_value, posX_16, posY_16):
|
|
config.set(section,letter + posX_16 + "," + posY_16, k_value)
|
|
config.set(section,letter + posX_16 + "," + posY_16, j_value)
|
|
config.set(section,letter + posX_16 + "," + posY_16, i_value)
|
|
config.set(section,letter + posX_16 + "," + posY_16, e_value)
|
|
config.set(section,letter + posX_16 + "," + posY_16, a_value)
|
|
|
|
#Needs work for choosing specific version of tilename (subtypes?), other versions of tiles (e.g. mm1electile1), and it also needs optional automatic room activator.
|
|
def set_tile(x, y, tilename="mm1cuttile", block_type="normal", tile_subtype=False, room_active=1):
|
|
by16 = conv_coordinates_x16(x, y)
|
|
x16 = str(by16[0])
|
|
y16 = str(by16[1])
|
|
|
|
if is_block_used(x, y):
|
|
#this needs a check to see if the coordinates are already taken, and deal with object-tile conflicts accordingly.
|
|
opt = get_options()
|
|
#WIP
|
|
option = 0
|
|
error = False
|
|
|
|
for letter in "kjiea":
|
|
if letter == "k":
|
|
#unknown, so sample for now. Related to tile sub type
|
|
#print("working k")
|
|
option = '"106.000"'
|
|
elif letter == "j":
|
|
#unknown Related to tile subtype. maybe this and k are x and y? This is x, not y.
|
|
#print("working j")
|
|
option = '"71.000"'
|
|
elif letter == "i":
|
|
#according to https://gist.github.com/freem/03d6c1832299e8d8a32f64361380920d this is block type
|
|
if block_type == "ladder":
|
|
option = '"3.000"'
|
|
elif block_type == "spike":
|
|
option = '"2.000"'
|
|
else:
|
|
option = '"1.000"'
|
|
elif letter == "e":
|
|
#supposedly this is item sub-type. Leaving default for now. Need to implement a method to have an index of all the tiles.
|
|
try:
|
|
tilename = int(tilename)
|
|
option = set_apos(tilename)
|
|
except ValueError:
|
|
if tilename in definitions.tile_names:
|
|
option = definitions.tile_names[tilename]
|
|
else:
|
|
error = True
|
|
#print("working e")
|
|
#option = '"3.000"'
|
|
else:
|
|
#enabled? Well, of course! Cheap way to remove a tile. Not ideal though, increases load time, proper removing of the keys will be implemented. ALERT, THIS APPLIES TO EVERYTHING NOT JUST TILES(objects, etc...)
|
|
#print("working a")
|
|
option = '"1.000"'
|
|
if error == False:
|
|
config.set(section,letter + x16 + "," + y16, option)
|
|
else:
|
|
return "error in " + str(letter)
|
|
|
|
def set_level_name(levelname):
|
|
config.set(section, alias["level_name"],set_apos(levelname))
|
|
|
|
def set_room_active(roomX, roomY,status=True): #the x and y values have to be the 0,0 relative to the room, so just the one where the tile on the top left corner of a room goes. I'll add this on set tile as a argument.
|
|
|
|
roomX = int(roomX) * 256
|
|
roomY = int(roomY) * 224
|
|
roomX = str(roomX)
|
|
roomY = str(roomY)
|
|
room_active = str(alias["room_active"])
|
|
if status == True:
|
|
status = '"1.000"'
|
|
else:
|
|
status = '"0.000"'
|
|
config.set(section,room_active + roomX + "," + roomY, status)
|
|
|
|
|
|
def set_player(x, y,type="mm", allow_duplicates=0):
|
|
by16 = conv_coordinates_x16(x, y)
|
|
x16 = str(by16[0])
|
|
y16 = str(by16[1]) #Every function that has something like all this should be a funcion.
|
|
for letter in "oda":
|
|
option = 0
|
|
if letter == "o":
|
|
#Unknown
|
|
option = '"9999.000"'
|
|
elif letter == "d":
|
|
#unknown
|
|
option = '"4.000"'
|
|
else:
|
|
option = '"1.000"'
|
|
config.set(section,letter + x16 + "," + y16, option)
|
|
|
|
def del_tile(x,y,disable=False):
|
|
for letter in definitions.block_with_coordinates:
|
|
current = letter + str(x) + ',' + str(y)
|
|
config.remove_option(section, current)
|
|
|
|
def set_ver(version=False):
|
|
if not version:
|
|
api_version = "https://api.megamanmaker.com/version"
|
|
ver = requests.get(api_version)
|
|
ver_num = ver.json()["version"]
|
|
else:
|
|
ver_num = version
|
|
set_setting(alias["game_version"], ver_num, True)
|
|
|
|
|
|
|
|
#def set_object(x, y, object_name, setting1):
|
|
# config.set(section, ) < I'll maybe add the set_player function here, because they are sort of objects. That way everything can be made through here.'
|
|
"""
|
|
< this will erase the entry for the tile, not just disable it. Maybe optional disable.
|
|
def list_tiles < this will return a list of tiles already on the level as a list each one with every of the 5 values for the 5 letters
|
|
|
|
def set_background
|
|
"""
|
|
#def set_ver(gamever) < this may support mega maker's api to get current version.'
|
|
|
|
# A problem that has to be fixed some day is that EVERY TILE WILL NOT APPEAR ON EDITOR TILL A PLAY TEST. It has something to do with the 1s, 1q,1p and 1r entries. I set the max value that works but on MMLV Editor the value changes if a tile is more torward the top left. Maybe an algorithm is needed to count every tile from the level and update those values accordingly.
|
|
read_file()
|
|
print(get_options())
|
|
set_setting("level_name", "does this work?")
|
|
set_ver()
|
|
write_changes("sample.mmlv")
|
|
|