Genji

Engaged Member
Dec 1, 2017
2,845
3,171
Mity is a good man,but dont let other people use him because of his goodness
 
D

Deleted member 436513

Guest
Guest
It's obvious that the artist feels some sort of obligation to the coder. Forgive my wording but this behaviour from the artist seems extremely 'feminine'. There is a reason that every business has a single boss, there is extreme utility in firing people who simply are not doing their job. I feel like many people here are extremely naive, this project is bringing in big dollars and the coder TAKES A 3 MONTH vacation, even 3 weeks seems excessive. From their postings it seems like he is working himself to death, but he has literally nothing to show for it other than extremely sloppy and shitty code.

After reading through your posts It's obvious that this entire project has been mismanaged from the very beginning. The artist, MITY has all the leverage, after all that's why people buy the game, not for the code but for the art. If this is a joint-project MITY needs to buy FET's share in the name and if he doesn't want to sell then threaten to leave him.

I legitimately think that he refused to patch up the game himself, because if he did he would outshine the coder. MITY wouldn't want to hurt his feelings so he stalls the project for 5 months.

For his next project i hope he hires a team of competent people and actually reinvents some money into his business.
Normally I'd say that's mean, but I think the crucial point that warrants it in this case is that their Patreon account hasn't been suspended during this entire shitshow, which is a major faux pas for me. Even if by mistake, that is a LOT of money.

That said, if you wanted to steelman the fuck out of MITY's side and view the whole thing from their perspective (at least with the limited information we've been given), it would go something like this:

1) The coder starts a project based on his original idea and vision, hires the artist based on some criteria, acts as the director for the game (every scene is his idea, he writes all the jokes, he comes up with the game flow and the overarching storylines, he manages the finances, etc. - all the artist does is follow instructions and essentially work on commission).
2) He does everything he possibly can to be generous (the Patreon stretch goals list "the coder will be employed full time" as the last goal, i.e. implying that the artist already got paid way before that, and him making enough money to quit his job is the least important requirement).
3) The project goes on and gets traction, he does everything he can to make his vision a reality, learns programming/game design/writing on the job, etc. He's never really done this before and they can't hire anyone else, so he'll have to spend a lot of time and effort to accomplish even basic things, but he won't give up, he'll try his best and he'll keep getting better.
4) They hit the "both of us quit our jobs" milestone ($6,000 in June 2017, less than a year after launch) and then... sort of just stop there. It's the two of us making a game, that's always been the plan after all, we don't know if we'll make enough to hire anybody else, we both live in an expensive area and we're in debt, why bother if there's a risk, so on and so on.
5) Then, the coder takes on more than he can handle as a beginner (the CCG minigame), gets burnt out/depressed as a result, and the artist goes "Alright dude we've been working together for 3 years, I know you, everything's gonna keep going fine. Just take a few weeks off, I'll keep working in the meantime, we'll delay the game a bit if we have to or I'll finish the update, no big deal".
6) Then he also breaks his ankle (?) during new year's eve (??) last month (???), and his mom had cancer before (or she still does?), and he's at his parents' house, whatever, real life. Let's assume things pile up and he's out of commission for 3 months through no fault of his own, he deserves a break, he really has been trying his best, it's fine. He's back on the job now, and everything is back to normal.
7) They also didn't really keep track of the Patreon money or think to suspend/invest it, so now they have the bad PR of making 80k for essentially no work.

Giving them the benefit of the doubt on all of that, we have the following possible criticisms:
  • The coder refuses to change things up, hire additional help, take a programming course, or recognize the limits of his own skills -> he's stubborn
  • The artist does most of the work, and actively harms the project by deferring to the coder instead of getting rid of or standing up to him, because of their friendship -> he's weak
  • They don't want to use the Patreon budget to improve the project, because they think they deserve to keep it to themselves -> they're greedy
Furthermore, MITY could host a minigame competition right now. Just ask people to submit Ren'py minigames which showcase their skills and fit for a project, he could offer 30% of the cashflow for the winner that gets hired. And of course if a new coder is a stranger, he will actually feel some pressure to improve due to the fear of being fired for subpar work.
I think your earlier point might hit a bit closer to home than anyone would want to admit. For instance, if the artist hired some guy to do the CCG minigame he failed to do, and he just DOES IT in a fucking weekend for 200 bucks, it's entirely possible the old coder would feel inadequate and spiral further into depression. The project management/HR side of things has always been the weakest aspect of FET, and it will continue to be so.
 
Last edited by a moderator:

Balrog

Active Member
Jan 10, 2018
665
1,084
Let's be honest, the spagheti code was a disaster waiting to happen and they were just lucky it took until book 3 and a CCG mini game to happen because it could have happened back in book 2.

Also sorry, but MITY never had the manpower and coding capacity to make a CCG mini game, at best they could do a memory game (like matching pairs between like 10 cards).

The game is good but they have to be realistic and either hire more people or rethink what they are planning.
 
D

Deleted member 436513

Guest
Guest
Also some quick maffs for those of you wondering:

You don't have permission to view the spoiler content. Log in or register now.

Assuming their stated goal of $6000 per month is enough to employ both of the people working on the project full time, i.e. that is their salary, they have $268,091 in reserve to do with as they please (before taxes). I don't mean to break out Marx, but god damn.
 
Aug 11, 2017
26
28
I don't even really see the point of deluding themselves people will care about CCG in a porn VN game.
Like, the game doesn't even really have good enough art to warrant such attention to it(those body proportions are not great, and the profile faces are completely wrong), why did they think a CCG would be important enough of a feature in this project?
They should've focused on integrating main plot with the game, making better minigames about that, and maybe improving at art, which none of what they've done.
 

FlipFish

Active Member
Oct 23, 2017
568
2,352
Limezero you're the real MVP here.

I really hope Mity tries to change his approach instead of trying to push on with his current management setup. I also see that mostly everyone agrees with the CCG thing. It's not that people inherently hate the idea, I for one loved Gwent in the Witcher 3, but one there's really no reason to throw it in a trainer game of all things and two it's too ambitious for this game and has already been causing plenty problems.
 

Balrog

Active Member
Jan 10, 2018
665
1,084
Also some quick maffs for those of you wondering:

You don't have permission to view the spoiler content. Log in or register now.

Assuming their stated goal of $6000 per month is enough to employ both of the people working on the project full time, i.e. that is their salary, they have $268,091 in reserve to do with as they please (before taxes). I don't mean to break out Marx, but god damn.
And they couldn't take like 3000 bucks out of that to hire a back up coder during the main coder's bulshit 3 month long vacation ?

That's YandereDev level of mismanagement TBH.
 
D

Deleted member 436513

Guest
Guest
...and here's a compilation of all the relevant Patreon updates since the last build of the game, for convenience's sake. In case somebody wants an overview and doesn't want to pledge or go digging through F95 posts.
You don't have permission to view the spoiler content. Log in or register now.
You don't have permission to view the spoiler content. Log in or register now.
You don't have permission to view the spoiler content. Log in or register now.
You don't have permission to view the spoiler content. Log in or register now.
You don't have permission to view the spoiler content. Log in or register now.
You don't have permission to view the spoiler content. Log in or register now.
You don't have permission to view the spoiler content. Log in or register now.
You don't have permission to view the spoiler content. Log in or register now.
You don't have permission to view the spoiler content. Log in or register now.
You don't have permission to view the spoiler content. Log in or register now.
 

lykos88

Newbie
Jan 15, 2018
94
53
Anyway i dont really want to say this if they are keeping taps you never know but why arent (P.a.t.r.e.o.n) bull the plug on this projekt.
It must been to amaunt of money the are getting for it them selfs.
No complains at all its hard find good content to fill my needs even when there are some management issues.
I dont believe they are making just some shit up to hide lazines etc.

Lastly i wont stop promoting wakfu for the next 1 even i think it is too early for that.
 

Xto

Newbie
Dec 1, 2017
17
15
Guys the "coder" created the project in the first place and he's also the primary writer, or at least contributes a similar amount as the artist. As mention previously, the artist goes by . MITY could even be the name the coder went by. You can't expect the artist to "fire" him (they're not even running a business, Patreon is a donation service) and just because he goes by "coder" doesn't mean it's necessarily the code he's struggling with.

Pretty much every writer experiences at some point. From Wikipedia, "blocks may be produced by adverse circumstances in a writer's life or career: physical illness, depression, the end of a relationship, financial pressures, or a sense of failure.", "It has been suggested that writer's block is more than just a mentality. Under stress, a human brain will 'shift control from the cerebral cortex to the limbic system'.", "The limbic system is associated with the instinctual processes, such as 'fight or flight' response".

He was physically injured, he's having to care for his sick mother, probably felt guilty about breaking the monthly schedule a number of times and wasting time on a minigame, now likely worrying about his future financial situation. I doubt it's an issue of "not feeling the pressure". Goodwill only goes so far.

Also, Limezero's post is a pretty severe misrepresentation of the code written for book 4.
  • "Number of files" is a totally meaningless metric for code size or complexity. They could put the entire game (372,111 lines) in one file if they wanted, or have 372,111 files consisting of one line.
  • The code definitely does not exist in just those two files. Sure, they might have a higher proportion of code to text compared to others, but all of the 41 .rpy files that make up book 4 (spanning 28,862 lines) contain logic or data, and possibly dialogue. A lot of it could be considered "boilerplate" (compositing images for example) but all of it had to be written.
  • The images shown are far from an accurate depiction of the extent of the complexity of the code. The DSL that RenPy supplies you with funnels inexperienced devs into a control flow nightmare. jump (goto) and global variables everywhere. Works alright for a classic VN with essentially no gameplay, but the moment you need a minigame, inventory, complex series of interacting choices... There's a reason practically every RenPy game update ships riddled with bugs (Summertime Saga had to progressively rewrite their codebase to use finite state machines).
Here's a better example of the kind of mess that will have someone wishing they weren't "the coder":
Python:
label korra_training:
    if amon_mask:
        if air_scroll ==2:
            if airbending ==7:
                show bfab bfab04 with dissolve
                kn "ready for more training?"
                show under_development_1
                show ctc
                pause
                hide ctc
                hide under_development_1
                jump b4_airtemple_map1
            if airbending ==6:
                if korra_spank_bj >=6:
                    if korra_foot_quest ==1:
                        show bfab bfab24 with dissolve
                        kn "ready for more training?"
                        kn "i... i promise i'll repay you."
                        if spinner_level >=10:
                            $ korra_foot_quest = 2
                            jump air_train3
                        else:
                            tn "(i need to level up to {b}10{/b} on the spinners before i can train more with korra.)"
                            jump bk4_training_menu
                    if korra_foot_quest ==0:
                        show bfab bfab24 with dissolve
                        kn "hey, tenzin...?"
                        tn "yeah?"
                        kn "i... i really need to get stronger."
                        kn "if you... i mean..."
                        kn "if you'll train with me some more..."
                        kn "i'll... i'll give you something."
                        tn "oh? what?"
                        kn "i... i don't know yet."
                        kn "but i promise it will be worth it!"
                        tn "...."
                        tn "okay."
                        $ korra_foot_quest = 1
                        if spinner_level >=10:
                            $ korra_foot_quest = 2
                            jump air_train3
                        else:
                            tn "(i need to level up to {b}10{/b} on the spinners before i can train more with korra.)"
                            jump bk4_training_menu
                else:
                    show bfab bfab04 with dissolve
                    kn "ready for more training?"
                    tn "soon, but not yet."
                    jump b4_airtemple_map1
            if airbending ==5:
                if k_protein <3:
                    tn "korra's waiting in her room for her protein shake."
                    jump b4_airtemple_map1
                else:
                    show bfab bfab04 with dissolve
                    kn "alright, what's next?"
                    tn "next, you're going to give me asami's number."
                    show bfab bfab24 with dissolve
                    kn "are you still on that?"
                    tn "yeah, and i'm gonna be... until i get her number."
                    tn "i'm tired of dialing random numbers."
                    tn "it's not an efficient system, and one man is very mad at me."
                    kn "....."
                    tn "....."
                    ta "give me that number!"
                    kn "okay, okay..."
                    kn "after today."
                    tn "fine."
                    hide black
                    show black with dissolve
                    "you practice the latest technique with korra, gaining efficiency in it."
                    hide black
                    show bfab bfab09
                    with dissolve
                    kn "yeah! love a good sweat!"
                    show bfab bfab04 with dissolve
                    kn "alright, tenzin... here's asami's number."
                    play sound "audio/win2.mp3"
                    "you got asami sato's phone number!"
                    tn "finally."
                    hide bfab with dissolve
                    tn "i should go somewhere private to make this phone call..."
                    tn "the tower, maybe?"
                    $ airbending = 6
                    jump b4_airtemple_map1
        if air_scroll ==1:
            if airbending ==4:
                if lin_buttstuff and korra_scroll2==0:
                    show bfab bfab04 with dissolve
                    tn "hey... so..."
                    tn "i need asami's phone number."
                    tn "phones are a thing by now, right?"
                    show bfab bfab24 with dissolve
                    kn "why..."
                    tn "it doesn't concern you."
                    kn "uh... i don't think she wants me to give it out..."
                    tn "come on. buddy. korra. pal. old friend. sloot."
                    kn "...what?"
                    tn "ignore that last one."
                    tn "help me out."
                    kn "mm... okay."
                    tn "great!"
                    show bfab bfab03 with dissolve
                    kn "in exchange for more training!"
                    tn "what?"
                    tn "but... i don't wanna."
                    show bfab bfab04 with dissolve
                    kn "come on... you haven't taught me anything real since that one scroll."
                    kn "let's do this!"
                    tx "uuughgh...."
                    tn "fine."
                    show bfab bfab03 with dissolve
                    kn "yay!"
                    tn "but first i need to... do something."
                    show bfab bfab24 with dissolve
                    kn "okay..."
                    hide bfab with dissolve
                    tn "...shit."
                    tn "where the fuck do i find a new airbending scroll?"
                    $ korra_scroll2 = 1
                    jump b4_airtemple_map1
                if korra_scroll2 ==1:
                    show bfab bfab04 with dissolve
                    kn "hey, ready to train me?"
                    tn "(i still don't have an airbending scroll...)"
                    tn "uh... almost."
                    show bfab bfab24 with dissolve
                    kn "oh... okay."
                    jump b4_airtemple_map1
                if korra_scroll2 ==2:
                    if spinner_level >=8:
                        show bfab bfab04 with dissolve
                        kn "ready?"
                        tn "actually, i am."
                        tn "read this."
                        show bfab bfab24 with dissolve
                        "you hand korra the scroll."
                        kn "this again..."
                        kn "fine, i guess i'll {i}read{/i}."
                        kn "like a dork."
                        hide black
                        show black with dissolve
                        "korra begins practicing the moves written on the scroll."
                        "you mimic her technique."
                        hide black
                        show bfab bfab09
                        with dissolve
                        kn "what a workout!"
                        show bfab bfab04 with dissolve
                        kn "not bad, tenzin."
                        tn "so... can i have asami's number now?"
                        show bfab bfab24 with dissolve
                        kn "i don't know..."
                        tn "oh, come on!"
                        kn "i'll... think about it, okay?"
                        kn "that's the best I can offer right now."
                        tn "...damn it."
                        kn "sorry, tenzin."
                        kn "now i need to go have my boring protein shake."
                        show bfab bfab05 with dissolve
                        kn "pema makes the worst shakes."
                        tn "...why don't you just make your own?"
                        show bfab bfab24 with dissolve
                        kn "pfft, yeah right."
                        kn "why would that be my responsibility?"
                        tn "....."
                        tn "sure."
                        kn "alright, terrible protein shake, here i come."
                        hide bfab with dissolve
                        tn "that... gives me an idea."
                        tn "i'll ask pema to help me with a... special one."
                        $ k_protein = 1
                        $ air_scroll = 2
                        $ airbending = 5
                        $ b4_daytime = False
                        jump b4_airtemple_map1
                    else:

                        show bfab bfab04 with dissolve
                        kn "hey, ready to train me?"
                        tn "(i need to be up to level 8 on the spinners to handle this move.)"
                        tn "not yet."
                        jump b4_airtemple_map1
                else:

                    tn "(still more to do elsewhere first.)"
                    jump b4_airtemple_map1
            if airbending ==3:
                if spinner_level < 6:
                    tn "i need to get to level 7 in the spinners to handle the next training session."
                    jump b4_airtemple_map1
                if spinner_level >=7:
                    if korra_rubbed >=3:
                        $ airbending = 4
                        jump air_train2
                    else:
                        tn "(my body is ready... but korra's isn't.)"
                        tn "(i need to lower her resistance, and maybe progress some more with her before the next training session.)"
                        jump b4_airtemple_map1

            if not air_scroll1_thought:
                tn "(alright, looking at this airbending scroll, i don't think i need to do anything special this time, actually.)"
                tn "(this one actually seems really straight forward.)"
                $ air_scroll1_thought = True
                show bfab bfab24 with dissolve
                kn "so...?"
                kn "you ready?"
            if spinner_level <5:
                tn "(crap, i need to spend more time on the spinners before i can train with this airbending move.)"
                tn "uh... not yet."
                kn "okay..."
                jump b4_airtemple_map1
            else:
                $ b4_daytime = False
                jump air_train1

    if not amon_mask:

        show bfab bfab04
        with dissolve
        kn "ready to train?"
        tn "(i still don't know any airbending techniques!)"
        tn "uh... not yet."
        kn "okay, i guess..."
        jump b4_airtemple_map1
Control flow like that is everywhere, especially "bk4_s_locations.rpy".

"3in1.rpy" (coin minigame) is just...
Python:
image kg = "bk4/backgrounds/park_day_1.jpg"
init python:
    import time
    style.mcnn=Style(style.default)
    style.mcnn.set_parent(style.button)
    style.mcnn.color="#beddff"
    style.mcnn.size=70
    style.mcnn.outlines=[(2,"#6e6e6e",0,0)]
    def krib():
        global cl1,cl2,cl3,cl4,cl5,cl6,cl7,kricol,krix,krix0,pointka,ktmr,clp1,clp2,clp3,clp4,clp5,clp6,clp7
        for i in range(0,9):
            if cl1[i]>0:
                clzz=1
                if i<7:
                    if cl1[i]==cl1[i+1]==cl1[i+2]:
                        pointka+=(cl1[i]+cl1[i+1]+cl1[i+2])*2
                        if i<6 and cl1[i]==cl1[i+3]:
                            if i<5 and cl1[i]==cl1[i+4]:
                                pointka+=cl1[i+4]*4
                                ktmr+=4
                                cl1[i+4]=0
                            pointka+=cl1[i+3]*3
                            ktmr+=2
                            cl1[i+3]=0
                        clzz,cl1[i+1],cl1[i+2]=0,0,0
                if cl1[i]==cl2[i]==cl3[i]:
                    pointka+=(cl1[i]+cl2[i]+cl3[i])*2
                    if cl1[i]==cl4[i]:
                        if cl1[i]==cl5[i]:
                            pointka+=cl5[i]*4
                            ktmr+=4
                            cl5[i]=0
                        pointka+=cl4[i]*3
                        ktmr+=2
                        cl4[i]=0
                    clzz,cl2[i],cl3[i]=0,0,0
                if clzz==0:
                    cl1[i]=0
        renpy.pause(0.05)
        for i in range(0,9):
            if cl2[i]>0:
                clzz=1
                if i<7:
                    if cl2[i]==cl2[i+1]==cl2[i+2]:
                        pointka+=(cl2[i]+cl2[i+1]+cl2[i+2])*2
                        if i<6 and cl2[i]==cl2[i+3]:
                            if i<5 and cl2[i]==cl2[i+4]:
                                pointka+=cl2[i+4]*4
                                ktmr+=4
                                cl2[i+4]=0
                            pointka+=cl2[i+3]*3
                            ktmr+=2
                            cl2[i+3]=0
                        clzz,cl2[i+1],cl2[i+2]=0,0,0
                if cl2[i]==cl3[i]==cl4[i]:
                    pointka+=(cl2[i]+cl3[i]+cl4[i])*2
                    if cl2[i]==cl5[i]:
                        if cl2[i]==cl6[i]:
                            pointka+=cl6[i]*4
                            ktmr+=4
                            cl6[i]=0
                        pointka+=cl5[i]*3
                        ktmr+=2
                        cl5[i]=0
                    clzz,cl3[i],cl4[i]=0,0,0
                if clzz==0:
                    cl2[i]=0
        renpy.pause(0.05)
        for i in range(0,9):
            if cl3[i]>0:
                clzz=1
                if i<7:
                    if cl3[i]==cl3[i+1]==cl3[i+2]:
                        pointka=(cl3[i]+cl3[i+1]+cl3[i+2])*2
                        if i<6 and cl3[i]==cl3[i+3]:
                            if i<5 and cl3[i]==cl3[i+4]:
                                pointka+=cl3[i+4]*4
                                ktmr+=4
                                cl3[i+4]=0
                            pointka+=cl3[i+3]*3
                            ktmr+=2
                            cl3[i+3]=0
                        clzz,cl3[i+1],cl3[i+2]=0,0,0
                if cl3[i]==cl4[i]==cl5[i]:
                    pointka+=(cl3[i]+cl4[i]+cl5[i])*2
                    if cl3[i]==cl6[i]:
                        pointka+=cl6[i]*3
                        ktmr+=2
                        cl6[i]=0
                    clzz,cl4[i],cl5[i]=0,0,0
                if clzz==0:
                    cl3[i]=0
        renpy.pause(0.05)
        for i in range(0,9):
            if cl4[i]>0:
                clzz=1
                if i<7:
                    if cl4[i]==cl4[i+1]==cl4[i+2]:
                        pointka+=(cl4[i]+cl4[i+1]+cl4[i+2])*2
                        if i<6 and cl4[i]==cl4[i+3]:
                            if i<5 and cl4[i]==cl4[i+4]:
                                pointka+=cl4[i+4]*4
                                ktmr+=4
                                cl4[i+4]=0
                            pointka+=cl4[i+3]*3
                            ktmr+=2
                            cl4[i+3]=0
                        clzz,cl4[i+1],cl4[i+2]=0,0,0
                if cl4[i]==cl5[i]==cl6[i]:
                    pointka+=(cl4[i]+cl5[i]+cl6[i])*2
                    clzz,cl5[i],cl6[i]=0,0,0
                if clzz==0:
                    cl4[i]=0
        renpy.pause(0.05)
        for i in range(0,7):
            if cl5[i]>0:
                if cl5[i]==cl5[i+1]==cl5[i+2]:
                    pointka+=(cl5[i]+cl5[i+1]+cl5[i+2])*2
                    if i<6 and cl5[i]==cl5[i+3]:
                        if i<5 and cl5[i]==cl5[i+4]:
                            pointka+=cl5[i+4]*4
                            ktmr+=4
                            cl5[i+4]=0
                        pointka+=cl5[i+3]*3
                        ktmr+=2
                        cl5[i+3]=0
                    cl5[i],cl5[i+1],cl5[i+2]=0,0,0
        renpy.pause(0.05)
        for i in range(0,7):
            if cl6[i]>0:
                if cl6[i]==cl6[i+1]==cl6[i+2]:
                    pointka+=(cl6[i]+cl6[i+1]+cl6[i+2])*2
                    if i<6 and cl6[i]==cl6[i+3]:
                        if i<5 and cl6[i]==cl6[i+4]:
                            pointka+=cl6[i+4]*4
                            ktmr+=4
                            cl6[i+4]=0
                        pointka+=cl6[i+3]*3
                        ktmr+=2
                        cl6[i+3]=0
                    cl6[i],cl6[i+1],cl6[i+2]=0,0,0
        for i in range(0,9):
            if cl6[i]==0:
                clp5[i]-=32
                if cl5[i]>0:
                    cl6[i]=cl5[i]
                    cl5[i]=0
                elif cl4[i]>0:
                    cl6[i]=cl4[i]
                    cl4[i]=0
                elif cl3[i]>0:
                    cl6[i]=cl3[i]
                    cl3[i]=0
                elif cl2[i]>0:
                    cl6[i]=cl2[i]
                    cl2[i]=0
                elif cl1[i]>0:
                    cl6[i]=cl1[i]
                    cl1[i]=0
                else:
                    cl6[i]=renpy.random.randint(1,6)
                for q in range(4):
                    clp5[i]+=8
                    renpy.pause(.0000001)
                ktmr+=0.1
        for i in range(0,9):
            if cl5[i]==0:
                clp5[i]-=32
                if cl4[i]>0:
                    cl5[i]=cl4[i]
                    cl4[i]=0
                elif cl3[i]>0:
                    cl5[i]=cl3[i]
                    cl3[i]=0
                elif cl2[i]>0:
                    cl5[i]=cl2[i]
                    cl2[i]=0
                elif cl1[i]>0:
                    cl5[i]=cl1[i]
                    cl1[i]=0
                else:
                    cl5[i]=renpy.random.randint(1,6)
                for q in range(4):
                    clp5[i]+=8
                    renpy.pause(.0000001)
                ktmr+=0.1
        for i in range(0,9):
            if cl4[i]==0:
                clp4[i]-=32
                if cl3[i]>0:
                    cl4[i]=cl3[i]
                    cl3[i]=0
                elif cl2[i]>0:
                    cl4[i]=cl2[i]
                    cl2[i]=0
                elif cl1[i]>0:
                    cl4[i]=cl1[i]
                    cl1[i]=0
                else:
                    cl4[i]=renpy.random.randint(1,6)
                for q in range(4):
                    clp4[i]+=8
                    renpy.pause(.0000001)
                ktmr+=0.1
        for i in range(0,9):
            if cl3[i]==0:
                clp3[i]-=32
                if cl2[i]>0:
                    cl3[i]=cl2[i]
                    cl2[i]=0
                elif cl1[i]>0:
                    cl3[i]=cl1[i]
                    cl1[i]=0
                else:
                    cl3[i]=renpy.random.randint(1,6)
                for q in range(4):
                    clp3[i]+=8
                    renpy.pause(.0000001)
                ktmr+=0.1
        for i in range(0,9):
            if cl2[i]==0:
                clp2[i]-=32
                if cl1[i]>0:
                    cl2[i]=cl1[i]
                    cl1[i]=0
                else:
                    cl2[i]=renpy.random.randint(1,6)
                for q in range(4):
                    clp2[i]+=8
                    renpy.pause(.0000001)
                ktmr+=0.1
        for i in range(0,9):
            if cl1[i]==0:
                clp1[i]-=32
                cl1[i]=renpy.random.randint(1,6)
                for w in range(4):
                    clp1[i]+=8
                    renpy.pause(.0000001)
                ktmr+=0.1
        return
screen krix:
    text "[pointk]" style "mcnn"
    text str(int(ktmr)) style "mcnn" xalign .99
    timer 1 repeat True action If(ktmr>0,true=SetVariable('ktmr',ktmr-1),false=Return())
    for z in range(1,7):
        for i in range(0,9):
            imagebutton idle ("bk4_xtra/3in1/k"+str(globals()["cl"+str(z)][i])+".png") xpos (i*80+260) ypos (z*80+20) action [SetVariable('krix',i),SetVariable('kriy',z),ui.callsinnewcontext("krich")]

    textbutton "I give up!" style "mcnn" xalign 0.5 yalign 0.9 action [SetVariable('ktmr',1)]

    if temp_int < 2:

        textbutton "Try again" style "mcnn" xalign 0.8 yalign 0.9 action [SetVariable('pointka',0),

            SetVariable('temp_int', temp_int+1),  Jump("krix")]


screen krixx:
    text "[pointk]" style "mcnn"
    text str(int(ktmr)) style "mcnn" xalign .99
    timer 1 repeat True action If(ktmr>0,true=SetVariable('ktmr',ktmr-1),false=Return())
    for z in range(1,7):
        for i in range(0,9):
            add ("bk4_xtra/3in1/k"+str(globals()["cl"+str(z)][i])+".png") xpos (i*80+260) ypos (z*80+20+globals()["clp"+str(z)][i])
label krich:
    show screen krixx
    if krix>=0:
        if krix in(krix0+1,krix0-1)and kriy==kriy0:
            pass
        elif kriy in(kriy0+1,kriy0-1)and krix==krix0:
            pass
        else:
            jump krich3
        if krix0>=0:
            $ krixxx=globals()["cl"+str(kriy)][krix]
            $ globals()["cl"+str(kriy)][krix]=globals()["cl"+str(kriy0)][krix0]
            $ globals()["cl"+str(kriy0)][krix0]=krixxx
            label krich2:
                $ krib()
                if pointka>0:
                    $ pointloop+=1
                    $ pointk+=pointka
                    $ pointka=0
                    jump krich2
                if pointloop==0:
                    $ krixxx=globals()["cl"+str(kriy0)][krix0]
                    $ globals()["cl"+str(kriy0)][krix0]=globals()["cl"+str(kriy)][krix]
                    $ globals()["cl"+str(kriy)][krix]=krixxx
                $ pointloop=0
                $ krix=-1
                $ krix0=-1
        else:
            label krich3:
                $ krix0=krix
                $ kriy0=kriy
    return
label krix:
    scene kg:
        ypos 0
    python:
        cl0,cl1,cl2,cl3,cl4,cl5,cl6,cl7,krix,kriy,kris,krin,kriw,krie,kricol,krix,krix0,kriy,kriy0,pointk,pointloop,ktmr,pointka=[],[],[],[],[],[],[],[],0,0,0,0,0,0,0,-1,-1,-1,-1,0,0,60,0
        for z in range(1,7):
            for i in range(0,9):
                globals()["cl"+str(z)].append(renpy.random.randint(1,6))
        clp0,clp1,clp2,clp3,clp4,clp5,clp6,clp7=[],[],[],[],[],[],[],[]
        for z in range(1,7):
            for i in range(0,9):
                globals()["clp"+str(z)].append(0)
    call screen krix
    return
Can't really blame RenPy for that one though.
 
Last edited:
  • Like
Reactions: Gekthegecko

H*A

Newbie
May 24, 2018
24
26
I mean, you don't have to look very hard to see the missteps that all people fresh to coding make. As you continue to explore, you'll often look back on prior work and think "What the fuck?"

There's a lot of things you learn along the way - better approaches, programming constructs, how something could be better achieved through use of X and/or following design pattern Y.

I don't think Mity, or anyone reads these threads, but hey.
If you were going to revisit old code or change approach --
Easy things to fix (not exclusive to Ren'Py, just OOP):
  • Use of classes (instead of global variables)
  • Helper functions (avoiding code repetition)
  • Use of appropriate design patterns
  • Avoiding bad design patterns
Just reading through an article or two on software design patterns would honestly be a great help to anyone stepping into this space - once they're somewhat comfortable with the basics.

It can be a fun and productive learning experience to attempt to solve problems without referencing existing solutions, but there's a lot of mistakes to be made when you're fresh to programming (and even when you're not). It also tends to be a bit of a crapshoot, if you're working to a deadline.

I think an issue a lot of people have with their personal conception of programming is that you just know how to approach a problem going in. The truth is that sometimes you don't have a great idea of how you're going to achieve something, but you do know what needs to happen.

Breaking things down into component bits and building it up, piece by piece, is both how you can make a tough problem achievable, and how you can work towards an easily maintainable codebase.

In any case, did not think I'd be writing up a post about the field I work in - not on this forum, at least. Bottom line for the responders here - I'd say the dude probably wants to build a marketable skill with programming. You know, something that you could put on a CV.
2016-20XX - "Worked on popular Western Erotica Game Cartoon Parody".
^ That one's a bit niche.
 
Last edited:
D

Deleted member 436513

Guest
Guest
Guys the "coder" created the project in the first place and he's also the primary writer, or at least contributes a similar amount as the artist. As mention previously, the artist goes by . MITY could even be the name the coder went by. You can't expect the artist to "fire" him (they're not even running a business, Patreon is a donation service) and just because he goes by "coder" doesn't mean it's necessarily the code he's struggling with.

[...]
Since this warrants a longer response, I'll be breaking it up into segments and responding to each. Note that my goal with these posts genuinely isn't to shit on MITY, they are far from the worst dev when it comes to goodwill, transparency or trying their hardest (especially the artist). I'm trying to be as neutral and fair as possible.

My main contention with "the coder" being the primary writer/programmer is that he's supposed to be THE ONLY writer/programmer. The artist coming in and writing or coding as much as 30-40% of the game speaks against him when compared with the artist. When you have Guy A who's drawing all the art, and doing potentially as much as half of the coder's programming and writing work, Guy B claiming to be burnt out raises a few eyebrows. Of course it's entirely possible that he's a different type of person who gets burnt out more quickly, but if I was in his situation, personally, I wouldn't feel like I "deserve" to complain or take time off when the other guy is essentially doing half of my work already in addition to his own.

I don't disagree with the notion of a writer's block, but... come on. I mean we're not exactly talking about Tolstoy here.

He was physically injured, he's having to care for his sick mother, probably felt guilty about breaking the monthly schedule a number of times and wasting time on a minigame, now likely worrying about his future financial situation.
Given that the art portion of the game was finished on August 24th at the latest and 0.8.3c came out Aug 14th, that leaves us with a timespan of roughly 4 months (119 days) to account for. Consult the timeline of events posted earlier for a more detailed breakdown, but suffice to say that the physical injury accounts for a two week period around the middle of November through December 5th (during which he also worked), caring for his sick mother is something that was mentioned in the past and is likely no longer applicable (he doesn't live with his parents, and staying with them seemed to be an unusual one time event), he has no reason to worry about his finances unless he owes money to a fucking Saudi oil magnate, and the artist told him to drop the CCG minigame and avoid getting burnt out way back in August before this entire thing began. Make of that what you will.

  • "Number of files" is a totally meaningless metric for code size or complexity. They could put the entire game (372,111 lines) in one file if they wanted, or have 372,111 files consisting of one line.
Hence why I included the filesizes in the screenshot (to give a rough estimate of how much code is involved - we're not talking about 3MB 78,000 LOC files. In this case it's 30k lines for Book 4, of which ~15k is boilerplate, ~15k is dialogue and ~2k is actual logic), selected the only two files with minigame code (i.e., programming), trimmed out the VN segments from even those, and brought up the example of the map screen and the day/night system as the most complex elements implemented in Ren'Py script as opposed to pure Python.

The intent was basically "if he hasn't even bothered to split it beyond two files, how much code do you think that is", and to show the ratio of what people understand as "programming" to everything else. But for the sake of transparency, this is what the entirety of Book 4 looks like (or it would, if it was organized):

overview0.png

_boilerplate is code that's self-explanatory (b4_eq1 is an equalist, their color is black, their side image is /equalist/sidebox/equalist_1.png, etc), _images are the sprite assignments ("bfau" is the Korra blowjob scene, it has 10 stages, stage 1 is /boobjob/body_1.png, stage 2 is /boobjob/ani_3.png, stage 3 is a 6 frame looping image with a 0.2 second delay between the frames etc), neither of them are terribly relevant, it's basically metadata that you wouldn't even use for future content.

Then we're left with code (which is the code for the minigames), and dialogue (which is the actual script and flow of the story).

You don't need to concern yourself with the minigame code, because you're not working on the minigames. The match-3 coin game is a fucking black box, you don't care what it does, and you don't care how it does it. Same with the blackjack minigame from Book 2. Yeah, it uses 18 files, all of them are identical, yeah 16 of those aren't even reached by the code, and yeah, all of them have a 52 element long if/else chain with variable names like "P6s" or "krix0". None of that is relevant. It does what it's supposed to, and it increments your money once it's finished. That's ALL YOU NEED TO KNOW. You don't need to touch it, you don't need to debug it, you let it sit there alone in the corner like the unloved abomination it is, and forget about its existence like its creator has.

Which then brings us to the only thing that involves logic you need to understand, the dialogue trees. Which make up ~16,000 lines of text, of which maybe 1000-2000 involve any kind of logic at all. Everything else is literally a book.

  • The code definitely does not exist in just those two files. Sure, they might have a higher proportion of code to text compared to others, but all of the 41 .rpy files that make up book 4 (spanning 28,862 lines) contain logic or data, and possibly dialogue. A lot of it could be considered "boilerplate" (compositing images for example) but all of it had to be written.
The reason I ignored those and why I'm overly dismissive of the VN side of things, is that I don't CONSIDER Ren'Py code to be fundamentally the same as programming. Note that I'm not saying "it takes no effort" either - writing DOES take effort. It just doesn't take the same kind of effort as programming in the conventional sense does. There are no classes you have to instantiate, you don't have to write unit tests, you don't need to know how A* search works, you don't have to be cautious when implementing cryptography, you don't have to write your own parser, you don't need to understand how binary formats work, you don't need to access a database, you don't have to work with matrices, you don't need to deal with the obscure bugs and API of the system you're running on, you don't have to worry about GC pauses, you don't need to worry about memory allocation, and I could keep going on and on. Ren'Py is control flow. That is ALL IT IS.

This...
Python:
    if spinner_level >=10:
        $ korra_foot_quest = 2
        jump air_train3
    else:
        tn "(i need to level up to {b}10{/b} on the spinners before i can train more with korra.)"
        jump bk4_training_menu
...is ALL you have to learn. That is the extent of the logic Ren'Py uses. Control flow.

It's a fundamentally different task that's much closer to writing and directing, and thus needs a different skillset. Same with the boilerplate code I mentioned like filename and image assignments, which make up almost as much of "the code" character-wise as the dialogue, follow a distinct formula, and could be easily offloaded to someone else with zero knowledge of the code or the script. Find the right filename, make sure it's on the right coordinates, make sure you put enough of a delay between frames that it looks the right speed, etc. They're glorified metadata files. It's busywork that you only even have to do in the first place because Ren'Py doesn't have a proper IDE or editor built around it which would handle it for you. It's the equivalent of manually renaming a hunded files in a directory. It doesn't take creativity or skill, it's not difficult, it just takes time. Christ, you could probably spend a few weeks putting together a basic graphical editor/preview tool for scenes or a PSD converter and save yourself months of effort down the line.

  • The images shown are far from an accurate depiction of the extent of the complexity of the code. Renpy is a thin layer over pygame. It grants you a DSL that funnels you into a control flow nightmare. jump (goto) and global variables everywhere. Works alright for a classic VN with essentially no gameplay, but the moment you need a minigame, inventory, complex series of interacting choices... There's a reason practically every RenPy game update ships riddled with bugs (Summertime Saga had to progressively rewrite their codebase to use finite state machines).
Yeah, and that's contention number #2. Even without the minigames and the Python side of things, EVEN amongst other VNs, Four Elements Trainer is very simple. The game doesn't HAVE an inventory system (ironically, because it might actually make things simpler). There are no complex series of interwoven choices which determine one of 17 possible outcomes with each character. The minigames don't affect your game state besides incrementing your money value or setting a flag to True. What you have are inline if/else choices with the dialogue listed right below, and scenes where the game outright fucking ASKS YOU which ending you'd like. Even as far as VN logic goes, FET's is firmly on the lower end of complexity.

Anyways, the reason I look down on VN code is because control flow isn't something you SHOULD have an issue with in the first place. It's something that's very easily visualized, and something that comes naturally to writing the story in the first place. If it becomes a problem because you didn't name your shit properly or you're deep within a nested loop of 19 elements, it's entirely a problem of your own creation. To illustrate what I mean, let's take a look at the two main components of Ren'Py code (ignoring boilerplate) - variables and control flow.

Suppose that you want to implement the Ember Island segment from Book 2 into the game.

You don't just start writing code from the get go, you do a million other things first. You decide on the idea, you talk it over with your partner, you think about what could be included, what the overall storyline would be, where it takes place in the game, and so on. You determine the scope of this update (an island in the love route, you interact with various girls, there's a crab minigame, the story involves azula warming up to you, we'll have these 13 scenes, the locations will be the beach, the house and the party you go to, the length is planned to be around five in-game days, etc).

In our mental map of the game's code, it's going to go right...

overview1.png

...there. So logically, it's only able to draw from or have an impact on variables here:

overview2.png

The only things that will be relevant to our Ember Island update are what has happened in the love route of book 2 so far, and what will happen in the love route of book 2 afterwards (which we're most likely not concerning ourselves with anyways, since we haven't even decided how the book is going to end yet). And if you were to finish the Ember Island update on your own as hired help for the project, the coder managing things would have to add a grand total of one (1) line of code to integrate it into the game: jump ember_island_start right at the end of that red section. You don't need to understand anything, and neither does the existing coder. Everything is modular and self-contained.

But why don't we make things more interesting? You start writing the story, and you reach a point as a writer where you decide that it would be a good idea to make a callback to a previous event. Let's say you're in a conversation with Azula and Mai, and there was a scene earlier in the Book 2 love route where you could choose to side with Azula or Mai respectively (which you know, because you've played the game already and/or wrote that scene yourself). You open the file that has a list of all of your variables for Book 2 (which you have, because you're not an idiot), you do a search for "azula" if you can't remember what it was called, find chosen_mai_over_azula, note that the comment above it says

Python:
#This variable is set to False if you told Azula about Mai in the shop during the second day of the love route, and True otherwise
and put that in your code. Then, for some reason you decide that one of the scenes in the Ember Island update will be influential on the story later, so you store the new variable island_azula_score, put it in your list, then add a comment above it which explains that

Python:
#This variable should be between 0-10 if you didn't get along with Azula, 10-20 if she was lukewarm towards you, and a perfect score of 23 is required for the special ending
followed by a breakdown of when it's possible to get points.

What you DON'T DO, is start fucking reading through the previous 293,400 lines of dialogue in the game and try to figure out where that variable was defined or when it gets modified, or HOPE that you can recall it every single time you need it. Because you're not fucking insane.



TL;DR - The problem is variables. The way you solve that problem is by having one of these:

variables.png

Let's take a look at problem number two. How do you comprehend this unwieldy chain of labels and quadruple-nested menu items and jumps and OH GOD

azu_throneroom_menu_1.png

Well first off, are you working on the Azula throneroom menu? No? Is the Azula throneroom menu going to be relevant in future content? What's that, "never again"? What the FUCK ARE YOU DOING here trying to read the code of the Azula throneroom menu, then? See the minigame rule above, close the file, forget about it, and go do something useful. Assuming the Azula throneroom menu actually IS relevant though, how would you go about comprehending this mess?

You don't. You separate the logic from the scenes, and read this instead:

azu_throneroom_menu_2.png

How do you memorize the complex relationship between jumps and how different labels link into each other?

You don't. You use one of these:

labels.png

Which you have, because you're not an idiot.




This became a rambly fucking mess and I'm too lazy to edit it down, sorry. The point is that if you were to be hired on right now to work on future content for the game, then
  • you ignore minigames and everything before the current book
  • you don't parse fifty million lines of code, you look at a tree of intro -> book4_map -> korra_room -> korra_training_menu -> korra_blowjob, and a list of variables
  • when writing a scene, you just write that standalone scene as its own thing with zero logic, code or labels, when coding minigames, you code that minigame separately as its own standalone project - i.e., you could be hired on as a writer or a programmer with ZERO knowledge of the game and have the existing guy implement your work
  • the order of how things should progress and what scenes should lead to what is ALREADY DECIDED beforehand, during the planning phase of the project, by someone doing the work of a director, which a writer then works off of and a programmer ties together with logic
  • understanding a call stack is the most basic component of programming, and is not even comparable to working on actual code
 
Last edited by a moderator:

H*A

Newbie
May 24, 2018
24
26
  • when writing a scene, you just write that standalone scene as its own thing with zero logic, code or labels, when coding minigames, you code that minigame separately as its own standalone project - i.e., you could be hired onto the project as a writer or a programmer with ZERO knowledge of the game and have the existing guy implement your work
This would likely be the easiest to implement, and have the biggest benefit to output.

Obviously you have to check state to decide what path to lead a player down, but well-structured and mostly distinct systems make it drastically easier to both track and isolate shoddy work, as well as avoid tech. debt that results from throwing things in wherever you can cram 'em.

As an aside: do you mean call stack here? Honestly, languages like Python make a big effort to abstract from anything to do with the call stack. I guess it's sort of a synonym for control flow - which could definitely be approached much better in FET's code.
 
Last edited:
D

Deleted member 436513

Guest
Guest
This would likely be the easiest to implement, and have the biggest benefit to output.

Obviously you have to check state to decide what path to lead a player down, but well-structured and mostly distinct systems make it drastically easier to both track and isolate shoddy work, as well as avoid tech. debt that results from throwing things in wherever you can cram 'em.

As an aside: do you mean call stack here? Honestly, languages like Python make a big effort to abstract from anything to do with the call stack. I guess it's sort of a synonym for control flow - which could definitely be approached much better in FET's code.
Wasn't sure what term to use, it's probably just control flow. Most of what you have in Ren'Py are labels (which are analogous to game "levels" or Unity scenes) that are on the same conceptual level of depth, nested if/else chains and menus which require you to keep track of how "deep" you currently are, and screens which are mostly used for UI overlays and minigames. Labels are pretty straightforward and naturally lend themselves to a linear A -> B graph/tree/whatever structure you can keep track of, similarly to how you'd have chapters one after the other in a book and a table of contents which you can use as an overview.

The "control flow" aspects of Ren'Py only become a problem if you start mixing the logic and the dialogue, leading you to doing stupid shit like copying and pasting the same ~1700 line long scene into three different locations which you have to maintain separately, or putting them inline (in-block?) with nested layers of logic, i.e.:

Python:
label falley_night2:
    if earth_deal:
        if tax_collector:
            if not tax_done:
                menu:
                    "kill him":
                        menu:
                            "donate the money":
                            "keep the money":
                    "knock him out":
                        menu:
                            "donate the money":
                                if variable >= 20:
                                    if flag == True:
                                        if condition:
                                        else:
                                            menu:
                                                "do it anyways":
                                                    if variable = 1:
                                                        "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
                                                        "Suspendisse porttitor arcu aliquet tortor vehicula, ut ultricies magna feugiat."
                                                        "Sed nec nunc non leo varius consequat eget sit amet orci."
                                                        "Curabitur malesuada nunc vitae tortor auctor facilisis."
                                                        $ variable += 2
                                                        "Praesent ut ligula sed augue scelerisque lobortis non dictum dui."
                                                        "Pellentesque nec tellus blandit, vestibulum lacus tincidunt, consectetur nibh."
                                                        "Donec sagittis nisl eu tellus aliquam, et accumsan ante maximus."
                                                        "Etiam aliquet turpis non ipsum consectetur, sit amet lacinia libero hendrerit."
                                                        "Pellentesque id diam at nulla ornare posuere."
                                                        "Sed accumsan tortor non eros pulvinar, sed varius magna eleifend."
                                                        "Donec non leo in elit rhoncus pellentesque."
                                                        "Phasellus in lacus posuere, dictum arcu vel, volutpat ipsum."
                                                        jump bk2_map
Or the fucking clown tier spaghetti code examples FET is known and loved for.

Untitled.png

Edit: Forgot to add that Ren'Py labels retain the current "state" when you swap them out (everything you've sent to the screen stays on the screen), so you COULD tehnically end up with something analogous to a call stack by doing the following:

Python:
label one:
    scene outside
    jump two

label two:
    show character with dissolve
    jump three

label three:
    play music "maintheme.ogg"
    jump four

label four:
    show othercharacter at left
    jump five

label five:
    c "Dialogue text"
    jump six
Which you wouldn't, because you're not what is known in the industry as "one hundred percent buttfuck insane". FET does suffer a bit from this (incidentally it's why it doesn't have a gallery/scene replay system either), but once again it's a problem you're creating for yourself and something that is still relatively easily fixable compared to debugging thousands of lines of actual logic.
 
Last edited by a moderator:
4.50 star(s) 276 Votes