Making a level with programming

View previous topic View next topic Go down

Making a level with programming

Post by garamond on Sat Dec 27, 2014 9:51 pm

I'm making a level which requires programming, so I've written some helper code, which I'm sharing here. For one level I already used it, for making a "fake" red rating -- the idea is the same as in "How to make "Blind Plays" Levels" tutorial -- i.e. how to position objects outside normal level limits. Except this post is about doing that with python programming.

One example is "it's time" by Snowtiger (the blue ratings just outside in the mini level preview). (I can't find my own level now :/ )

I'm posting the code here.
By modifying move_exampe() you can move objects. More specific directions are written there.

The code can do much more. You can also add objects programatically -- add_mines_example() adds a diagonal with 70 mines.

Maybe somebody can use this for whatever reason :)

Code:
import operator


empty_objects = {  # "name": (position number in data, num of bytes, data)
    "player" : (0, 2, ""),
    "mine" : (1, 2, ""),
    "gold" : (2, 2, ""),
    "exit" : (3, 4, ""),
    "regular_door" : (4, 3, ""),
    "locked_door" : (5, 5, ""),
    "trap_door" : (6, 5, ""),
    "launchpad" : (7, 3, ""),
    "oneway" : (8, 3, ""),
    "chaingun" : (9, 4, ""),
    "laser" : (10, 4, ""),
    "zap" : (11, 4, ""),
    "chaser" : (12, 4, ""),
    "floorguard" : (13, 2, ""),
    "bounceblock" : (14, 2, ""),
    "rocket" : (15, 2, ""),
    "gauss" : (16, 2, ""),
    "thwump" : (17, 3, "")
}


def move(objects, type, diff_x, diff_y, pos_start):

    orig = objects[type]
    num, b, original_objects = orig
    new_objects = ""
    length = b * 2

    for i in range((len(original_objects) - 4) // length):
        rev_hex_x = original_objects[4 + i * length + pos_start : 4 + i * length + pos_start + 2]
        rev_hex_y = original_objects[4 + i * length + pos_start + 2 : 4 + i * length + pos_start + 4]

        final_x = dec_to_reverse_hex(hex_to_dec(rev_hex_x) + diff_x)
        final_y = dec_to_reverse_hex(hex_to_dec(rev_hex_y) + diff_y)

        temp = original_objects[4 + i * length : 4 + i * length + length]
        temp = list(temp)

        temp[pos_start + 0] = final_x[0]
        temp[pos_start + 1] = final_x[1]
        temp[pos_start + 2] = final_y[0]
        temp[pos_start + 3] = final_y[1]

        new_objects += "".join(temp)
    #print(new_objects)
    objects[type] = num, bytes, original_objects[0:4] + new_objects


def add_object(objects, type, object_data):
    orig = objects[type]
    num, bytes, original_objects = orig
    num_original = hex_to_dec(original_objects[0:4])
    num_added = hex_to_dec(object_data[0:4])
    objects[type] = num, bytes, dec_to_reverse_hex_byte(num_original + num_added) + original_objects[4:] + object_data[4:]


def hex_to_dec(reverse_hex_string):
    if reverse_hex_string == "00" or reverse_hex_string == "0000":
        return 0
    if len(reverse_hex_string) == 2:
        return int(reverse_hex_string[::-1], 16)
    else:  # len is 4
        first = int(reverse_hex_string[0:2][::-1], 16)
        second = int(reverse_hex_string[2:4][::-1], 16)
        return first * 16 * 16 + second


def dec_to_reverse_hex(dec):
    num = (hex(dec)[2:])[::-1]  # we've got no negative numbers
    if len(str(num)) == 1:
        return str(num) + "0"
    return num


def dec_to_reverse_hex_byte(dec):
    num = (hex(dec)[2:])  # we've got no negative numbers
    if len(str(num)) == 1:
        return "00" + str(num) + "0"
    if len(str(num)) == 2:
        return "00" + str(num)[1] + str(num)[0]
    if len(str(num)) == 3:
        return str(num)[0] + "0" + str(num)[2] + str(num)[1]
    if len(str(num)) == 4:
        return str(num)[1] + str(num)[0] + str(num)[3] + str(num)[2]


def serialise(objects, data):
    pos = 0
    sorted_objects = sorted(objects.items(), key=operator.itemgetter(1))
    for item in sorted_objects:
        num_objects = hex_to_dec(data[pos : pos + 4])
        till_next = num_objects * item[1][1] * 2
        objects[item[0]] = item[1][0], item[1][1], data[pos : pos + 4 + till_next]
        #print("#: " + str(item[1][0]), "position: " + str(pos), "num_objects: " + str(num_objects))
        pos += till_next + 4


def pack(objects):
    packed = ""
    sorted_objects = sorted(objects.items(), key=operator.itemgetter(1))
    for item in sorted_objects:
        packed += (item[1][2])
    return packed


def move_example():
    # paste here level data from N Editor. Remove level name in the beginning, if it's present
    data = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000087017511751165900590f4a0f4e0f41125c0759045907511f4c065e045a045c025e00501250165a00581755145510551f461f4a1f4d125c175d175d165d1f451758165614561058125a105a145c125c16542751245120512f422f462f4922582759275926592f41275426522452205422562056245822582650375d245d205d2f4e2f423f4532543755375536553f4d2750365e245e20503252305234543254365c3759345930593f4a3f4e3f4142504751475146514f49375c365a345a305c325e305e3450425046584755445540554f464f4a4f4d425c475d475d465d4f454758465644564058425a405a445c425c465000000000000000000000000000000000003c0450020c00500200105002001450020a0650020e0650020e0250020a02500208145002081050020c1050020c1450020a125002061650020a16500206125002042450020420500208205002082450020622500202265002062650020222500200345002003050020430500204345002023250020e265002023650020e2250020c3450020c30500200405002004450020e3250020a3650020e3650020a32500208445002084050020c4050020c4450020a425002064650020a4650020642500200000000000000000000000000000"
    new = data[1426 + 8:]  #only objects
    objects = empty_objects.copy()
    serialise(objects, new)
    # Specify objects that you want to move. List of names is in the beginning of this file
    # "135" means move object for roughly a level width to the right
    move(objects, "laser", 135, 0, 0)
    move(objects, "mine", 135, 0, 0)
    print(data[0:1426 + 8] + pack(objects))


def draw_many_doors_example():
    data = "0000" * 18
    objects = empty_objects.copy()
    serialise(objects, data)

    # add many many doors
    for i in range(128 + 1 - 4):  #128
        for j in range(94 // 2):  #94
            add_object(objects, "locked_door", "0010" + dec_to_reverse_hex(i + 4) + dec_to_reverse_hex(j * 2 + 4) + "00" + "8080")

    for i in range(128 // 4 - 4):  #128
        for j in range(94):  #94
            add_object(objects, "locked_door", "0010" + dec_to_reverse_hex(i * 4 + 4) + dec_to_reverse_hex(j + 4) + "20" + "8080")

    #print(sorted(objects.items(), key=operator.itemgetter(1)))
    print(dummy_blocks + pack(objects))


def add_mines_example():
    data = "0000" * 18
    objects = empty_objects.copy()
    serialise(objects, data)

    # add single mine
    add_object(objects, "mine", "0010ffff") # 0010 is 1 mine, ff is position x, ff is position y

    # add 70 mines in a diagonal line
    for i in range(70):
        add_object(objects, "mine", "0010" + dec_to_reverse_hex(i) + dec_to_reverse_hex(i))

    print(dummy_blocks + pack(objects))


# dummy_blocks + empty objects data = empty level
dummy_blocks = "00000000" + "00" * 31 * 23 # "00" is empty block
data = "0000" * 18

#move_example()
#draw_many_doors_example()
add_mines_example()
If you don't have python installed, you can play with it on http://repl.it/7EL

garamond
Admin

Messages : 21
Joined : 2014-11-16

View user profile

Back to top Go down

View previous topic View next topic Back to top

- Similar topics

 
Permissions in this forum:
You cannot reply to topics in this forum