Putting the 'role' back in role-playing games since 2002.
Donate to Codex
Good Old Games
  • Welcome to rpgcodex.net, a site dedicated to discussing computer based role-playing games in a free and open fashion. We're less strict than other forums, but please refer to the rules.

    "This message is awaiting moderator approval": All new users must pass through our moderation queue before they will be able to post normally. Until your account has "passed" your posts will only be visible to yourself (and moderators) until they are approved. Give us a week to get around to approving / deleting / ignoring your mundane opinion on crap before hassling us about it. Once you have passed the moderation period (think of it as a test), you will be able to post normally, just like all the other retards.

Might and Magic The Might and Magic Discussion Thread

What is the best Might & Magic game in the series?

  • Might and Magic: Book I

    Votes: 17 2.3%
  • Might and Magic II: Gates to Another World

    Votes: 29 3.9%
  • Might and Magic III: Isles of Terra

    Votes: 59 8.0%
  • Might and Magic: World of Xeen

    Votes: 182 24.6%
  • Might and Magic: Swords of Xeen

    Votes: 5 0.7%
  • Might and Magic VI: The Mandate of Heaven

    Votes: 210 28.4%
  • Might and Magic VII: For Blood and Honor

    Votes: 129 17.4%
  • Might and Magic VIII: Day of the Destroyer

    Votes: 26 3.5%
  • Might and Magic IX

    Votes: 10 1.4%
  • Might and Magic X

    Votes: 73 9.9%

  • Total voters
    740

TheDeveloperDude

MagicScreen Games
Developer
Joined
Jan 9, 2012
Messages
412
in 7 does no one choose Light?
I think plenty of people do. Light Magic is actually pretty powerful when it comes to party buffs, where it lacks the direct damage output of Dark Magic.
Yes, I have played MM7 choosing the Light Path. It has so big defense, enemy could not hurt my party, and I killed everything using weapons. If I remember correctly.

Which one looks better?
Hardware renderer (Grayface HR version):


Software renderer:


I prefer the old software renderer, it has better mood.

Are these Merge features? I have 3 spell master NPCs, that is +12 magic skills.
In pure MM6/7/8 these were not cumulative, only +4 ?
Same change for SP regeneration items?
 

Red Hexapus

Savant
Joined
Apr 28, 2019
Messages
321
Location
The Land of Potato
So... some of my friends tend to screen very shitty movies in a local pub every Monday. Imagine my surprise, when I saw Might & Magic III in a movie being screened tonight.
The movie is Scary Tales from 1993 and it's really shitty. Proof below at 47:52.

 

KeighnMcDeath

RPG Codex Boomer
Joined
Nov 23, 2016
Messages
13,062
IMG_0937.jpeg

Man, that dude sucks and so does his computer. How many times did he keep rebooting in that scene?
 

Grunker

RPG Codex Ghost
Patron
Joined
Oct 19, 2009
Messages
27,418
Location
Copenhagen
I almost always go light in MM7, mainly because I think it has more QoL. Hour of Power especially is just QoL incarnate.
 

jackofshadows

Magister
Joined
Oct 21, 2019
Messages
4,545
HoP multiplies buffs though so it's much more than just QoL, same for day of protection. Also, caster focused party doesn't really need those buffs.
 

Grunker

RPG Codex Ghost
Patron
Joined
Oct 19, 2009
Messages
27,418
Location
Copenhagen
it's much more than just QoL

Obviously. But QoL is the reason I like to go that route.

I also never go pure cast. I almost always go Knight - Hybrid - Hybrid - Purecaster. It allows me more options and is generally weaker than most parties, which is good, because these games are easy enough as it is.
 

jackofshadows

Magister
Joined
Oct 21, 2019
Messages
4,545
It allows me more options and is generally weaker than most parties, which is good, because these games are easy enough as it is.
I agree that's why I was taking another shitty hybrid instead of knight when did runs like that. Skipping on a proper caster too and use npcs instead is too much for me though, always autistically take +10 and +15 learning guys in mm7.
 

Grunker

RPG Codex Ghost
Patron
Joined
Oct 19, 2009
Messages
27,418
Location
Copenhagen
It allows me more options and is generally weaker than most parties, which is good, because these games are easy enough as it is.
I agree that's why I was taking another shitty hybrid instead of knight when did runs like that. Skipping on a proper caster too and use npcs instead is too much for me though, always autistically take +10 and +15 learning guys in mm7.

Yeah, I really enjoyed my Monk - Thief - Cleric - Wizard run. Monks get GM learning!
 

Mauman

Learned
Joined
Jun 30, 2021
Messages
935
Both light and dark are great. I've played both light and dark side of mm7 multiple times and I always feel the loss of the other.

I appreciate that I don't have to choose with the merge mod.

Also, I was just testing the mm6 skill switchers in blackshire. They work perfectly. You want a Lich with light magic GM? You can do that. A priest of the Sun with dark? Yup. You can switch back and forth with no penalty to the skills themselves (if you were dark Grand, now you're an equal level of Light Grand). Only thing is you have to relearn your spells. Which is a bit annoying.

It's a wee bit silly :P
 

Lonely Vazdru

Pimp my Title
Joined
Jan 10, 2007
Messages
6,659
Location
Agen
And 13 years after its creation, the holy Might and Magic thread reached 300 pages. John Van Caneghem looked down upon its creation's legacy and saw that it was good. And there was much rejoicing...

:bioware::happytrollboy::popcorn::mlady::love::majordecline::codexisfor::greatjob::brodex::desu:
 

Morpheus Kitami

Liturgist
Joined
May 14, 2020
Messages
2,547
Wasn't there some word about a Chinese studio developing a Might & Magic project? Conventional wisdom says it will be a cheap mobile cash grab, and not a proper RPG. But nothing's been confirmed.
Considering that there have already been 2 mobile games (IIRC) made by some Asian company, I highly doubt they'll change a "winning" formula.
 

behold_a_man

Educated
Joined
Nov 26, 2022
Messages
144
So, I've finished the third one.
finale_large.png

Note that dead mercenaries are unable to collect the money you owe them.



My observations after playing it are:
1) I enjoyed puzzles in this game: especially the idea that there are in-game solutions to the puzzles, which allows to create much tougher and simultaneously more rewarding puzzles without forcing the player to solve each of them in order to complete the game; yet, when the player gets the solutions, the rewards (except for completing the game) are barely relevant. Also, brute-forcing puzzles was oftentimes feasible but still required some sort of general strategy or idea in order to solve them quickly - like evaluating at least the later part of the expression in the Arachnoid Caves or using the Gray code in the Greywind Castle.
Perhaps the most unique thing about them I noticed was using them as a means of presenting some stories; for example, in the dungeons below Castle Windshield, there are scattered parts of a dwarven rhyme:
The good King Zealot was quite a knave,
To his wife and her lover a box he gave,
His wife's young lover was an orc named Smello,
With hell-hound's breath and hair of yellow,
The queen was shocked by her pine box,
For the open end had golden locks,
Smello's box sent him reeling,
And wooden planks were his last feeling,
The countersign lies in the queen's box.

And the
Smello
. While I admire the idea, I don't think it was a good riddle:
the next to last verse seemed to imply that Smello was alive when the box was opened, which kind of doesn't make sense.

There were some other scuffed puzzles. Case in point - this riddle in the Cursed Cold Cavern:
riddle_large.png

With the
chain.
Brave to say this in a world where wooden chainmail is the latest fashion trend. I expected the answer to be some sort of mineral that forms bubble-wrap-like structures.

I think the writers should care about precision in their wording when writing such enigmas - or, even better, get people experienced with writing technical documentation to create them.


2) I liked how almost all of the dunegons had some differentiating characteristics: Dragon Cavern featuring dragons and tons of gold; Blackwind dungeon with its invisible teleports; Cathedral of Carnage filled to the brim with spells to learn; or The Arachnoid Cavern with a puzzle forcing you to learn a lot about the structure of a dungeon - if you wanted to get those bonuses to stats while they were still relevant. Also, I don't think I ever saw before dungeons constantly referencing other dungeons; I think it added some tension to exploration - like constantly seeing remarks about the Maze From Hell being quite an unpleasant location.

3) Another pleasing idea in this game is that the player was rewarded for exploration with simplification of exploration (getting swimming or mountaineering; walk on water and other positional spells; portal activation words) - though I wouldn't expect anything else from a game in this series. In most open-world games I saw, the later I was in the game, the more boring traversing the world was; here, I got the Interspacial Transport Box allowing me to traverse the entire world almost instantly in the penultimate dungeon.

4) The game was possible to complete using only a keyboard, and all actions were effectively discrete; the obvious implication is that the game should (and was) quite fast; the less obvious is that it could be scripted - for example, I wrote some simple scripts that pressed key combinations, allowing me to buff automatically (spells + Blistering Heights statues + Well on D1 giving +100 to everything) or repair all the broken equipment after eradication without needing to lift a finger. I would love to see a game allowing me to write scripts using internal information about the state of the game - for example, in case of this game, what is my position+direction on the map, which parts of equipment are broken, or what is the status of my company - so that it would be possible to receive feedback from the game without resorting to processing screenshots.

I preferred this game to the sixth and seventh ones; I didn't feel like the game was punishing me for progress with subsequent tiresome encounters or, even worse, Castle Darkmoor.
 

solemgar

Educated
Patron
Joined
Aug 3, 2023
Messages
146
Location
Mechanus
Codex+ Now Streaming!
So, I've finished the third one.
finale_large.png

Note that dead mercenaries are unable to collect the money you owe them.



My observations after playing it are:
1) I enjoyed puzzles in this game: especially the idea that there are in-game solutions to the puzzles, which allows to create much tougher and simultaneously more rewarding puzzles without forcing the player to solve each of them in order to complete the game; yet, when the player gets the solutions, the rewards (except for completing the game) are barely relevant. Also, brute-forcing puzzles was oftentimes feasible but still required some sort of general strategy or idea in order to solve them quickly - like evaluating at least the later part of the expression in the Arachnoid Caves or using the Gray code in the Greywind Castle.
Perhaps the most unique thing about them I noticed was using them as a means of presenting some stories; for example, in the dungeons below Castle Windshield, there are scattered parts of a dwarven rhyme:
The good King Zealot was quite a knave,
To his wife and her lover a box he gave,
His wife's young lover was an orc named Smello,
With hell-hound's breath and hair of yellow,
The queen was shocked by her pine box,
For the open end had golden locks,
Smello's box sent him reeling,
And wooden planks were his last feeling,
The countersign lies in the queen's box.

And the
Smello
. While I admire the idea, I don't think it was a good riddle:
the next to last verse seemed to imply that Smello was alive when the box was opened, which kind of doesn't make sense.

There were some other scuffed puzzles. Case in point - this riddle in the Cursed Cold Cavern:
riddle_large.png

With the
chain.
Brave to say this in a world where wooden chainmail is the latest fashion trend. I expected the answer to be some sort of mineral that forms bubble-wrap-like structures.

I think the writers should care about precision in their wording when writing such enigmas - or, even better, get people experienced with writing technical documentation to create them.


2) I liked how almost all of the dunegons had some differentiating characteristics: Dragon Cavern featuring dragons and tons of gold; Blackwind dungeon with its invisible teleports; Cathedral of Carnage filled to the brim with spells to learn; or The Arachnoid Cavern with a puzzle forcing you to learn a lot about the structure of a dungeon - if you wanted to get those bonuses to stats while they were still relevant. Also, I don't think I ever saw before dungeons constantly referencing other dungeons; I think it added some tension to exploration - like constantly seeing remarks about the Maze From Hell being quite an unpleasant location.

3) Another pleasing idea in this game is that the player was rewarded for exploration with simplification of exploration (getting swimming or mountaineering; walk on water and other positional spells; portal activation words) - though I wouldn't expect anything else from a game in this series. In most open-world games I saw, the later I was in the game, the more boring traversing the world was; here, I got the Interspacial Transport Box allowing me to traverse the entire world almost instantly in the penultimate dungeon.

4) The game was possible to complete using only a keyboard, and all actions were effectively discrete; the obvious implication is that the game should (and was) quite fast; the less obvious is that it could be scripted - for example, I wrote some simple scripts that pressed key combinations, allowing me to buff automatically (spells + Blistering Heights statues + Well on D1 giving +100 to everything) or repair all the broken equipment after eradication without needing to lift a finger. I would love to see a game allowing me to write scripts using internal information about the state of the game - for example, in case of this game, what is my position+direction on the map, which parts of equipment are broken, or what is the status of my company - so that it would be possible to receive feedback from the game without resorting to processing screenshots.

I preferred this game to the sixth and seventh ones; I didn't feel like the game was punishing me for progress with subsequent tiresome encounters or, even worse, Castle Darkmoor.
I like the script part. How did you write them?
 

behold_a_man

Educated
Joined
Nov 26, 2022
Messages
144
I like the script part. How did you write them?
This is an example of the actual script - the one I used for buffing:
Python:
from pynput.keyboard import Key, Controller
import time

SLEEP_BEFORE_START = 3
SLEEP_TIMES = {
        'movement': 0.15,
        'yes no': 0.2,
        'regular spell': 0.6,
        'altar change location': 8,
        'teleport no location change' : 1.2,
        'teleport change location': 6
}
SORCERER_POSITION = 5
CLERIC_POSITION = 4

SPELL_POSITION_SORCERER = {
        'teleport' : 21,
        'power shield' : 16,
}

SPELL_POSITION_CLERIC = {
        'blessed': 14,
        'holy bonus': 15,
        'heroism': 17
}

keyboard = Controller()

def banal_click(to_press, time_sleep = SLEEP_TIMES['movement']):
    keyboard.press(to_press)
    keyboard.release(to_press)
    time.sleep(time_sleep)

def move_forward(amount):
    to_press = Key.up
    for x in range(amount):
        banal_click(to_press)

def spell(person=None, spell_number=-1, additional = (), post_wait = SLEEP_TIMES['regular spell']):
    spell_button = 'c'
    banal_click(spell_button)
    if person:
        to_press = Key.__getattr__(f'f{person}')
        banal_click(to_press)

    if spell_number >= 0:
        banal_click('n')
        for x in range(spell_number-10):
            banal_click(Key.down)
        if spell_number >= 10:
            banal_click('0')
        else:
            banal_click(spell_number)
        banal_click('s')

    banal_click(spell_button)
    for button in additional:
        banal_click(button)
    time.sleep(post_wait)


def turn_left():
    banal_click(Key.left)

def turn_right():
    banal_click(Key.right)

def yes():
    banal_click('y', SLEEP_TIMES['yes no'])

def no():
    banal_click('n', SLEEP_TIMES['yes no'])

def spell_buffing():
    for spell_number in [SPELL_POSITION_CLERIC[_] for _ in ('blessed', 'holy bonus', 'heroism')]:
        first_time = False
        for key in [Key.f1, Key.f2]:
            spell(person=CLERIC_POSITION, spell_number=-1 if first_time else spell_number, additional = (key,), post_wait=SLEEP_TIMES['regular spell']) #Spellcaster's Buffs (No protection from elements
            first_time = True

    time.sleep(1)
    first_time = False
    for key in [Key.__getattr__(f'f{_}') for _ in range(1, 7)]:
        spell(person=SORCERER_POSITION, spell_number=-1 if first_time else SPELL_POSITION_SORCERER['power shield'], additional = (key,), post_wait=SLEEP_TIMES['regular spell']) #Spellcaster's Buffs (No protection from elements
        first_time = True

def write(txt):
    for _ in txt:
        banal_click(_)
    banal_click(Key.enter)

def to_the_well():
    turn_right()
    turn_right()
    spell(SORCERER_POSITION, SPELL_POSITION_SORCERER['teleport'], ('4', Key.enter), SLEEP_TIMES['teleport no location change'])
    turn_right()
    spell(SORCERER_POSITION, additional = ('9', Key.enter), post_wait = SLEEP_TIMES['teleport change location'])
    spell(SORCERER_POSITION, additional = ('5', Key.enter), post_wait = SLEEP_TIMES['teleport no location change'])
    spell(SORCERER_POSITION, additional = ('9', Key.enter), post_wait = SLEEP_TIMES['teleport change location'])
    spell(SORCERER_POSITION, additional = ('9', Key.enter), post_wait = SLEEP_TIMES['teleport no location change'])
    turn_right()
    yes()
    yes()
    yes()

def sequencer(*args):
    for x in args:
        if type(x) == int:
            move_forward(x)
        if x == 'l':
            turn_left()
        if x == 'r':
            turn_right()
        if type(x) == tuple and x[0] == 's':
            spell(**x[1])
        if type(x) == str and x[0] == 'y': #yes + amount of times to execute it
          amount = 1
          if len(x) > 0:
              amount = int(x[1:])
          for _ in range(amount):
              yes()

        if x == 'n':
            no()
        if x=='t': #turn around
            turn_right()
            turn_right()

def resistances_to_well():
    sequencer('t', 1, 'l', 4, 'r', 1, 'y1')
    time.sleep(1)
    write('air')
    time.sleep(SLEEP_TIMES['altar change location'])
    to_the_well()

time.sleep(SLEEP_BEFORE_START)
# Start: face North, (14, 6) - Blistering Heights (location after Town Portal / Box use)
spell_buffing()
time.sleep(2)
sequencer(2, 'l', 3, 'y2', 4, 'n', 4, 'y2', 't', 4, 'n', 'l', 4, #Here - elemental resistances
       'y2', 't', 4, 'n', 5, 'y2')
time.sleep(2)
resistances_to_well()

Note that I have to start at a certain place ((14, 6) - Blistering Heights) facing north. SLEEP_BEFORE_START determines the time I need to switch context to a game - the only thing this script does is pressing buttons and waiting. It's probably possible to send keys directly to the process, but I don't think it would be very portable. All the sleeping times were subjected to tinkering.
Now, obviously, this code is not very polished. I started by writing something like
Python:
from pynput.keyboard import Key, Controller
import time
keyboard = Controller()

time.sleep(3)
keyboard.press(Key.up)
keyboard.release(Key.up)
time.sleep(0.1)
keyboard.press(Key.up)
keyboard.release(Key.up)
time.sleep(0.1)

And then gradually moved all the repeating parts into functions, and some repeating hardcoded variables into constants. There are some Python hacks - like using __getattr__ to get an attribute of the Key class from a string or dictionary unpacking (**some_list) to easily pass a dictionary as a list of arguments to a function - but you can avoid them (albeit the code will be even less concise).
The only visible and obvious problems are the fact that I need to start facing the exact direction and know the position of a spell in a list of each character; the lack of feedback gets more frustrating when it comes to repair:
Python:
from pynput.keyboard import Key, Controller
import time

TIME_SLEEP = 0.15
keyboard = Controller()
def banal_click(to_press, time_sleep = TIME_SLEEP):
    keyboard.press(to_press)
    keyboard.release(to_press)
    time.sleep(time_sleep)

sizes = [-1, 17, 0, 17, 0, 0, 16] # This fixes 17 first items of the person under F1, 0 from person under F2 etc. -1 starts the list here, because F0 doesn't exist, and indexing in python starts from 0.

time.sleep(3)
for person_to_repair in range(1, 7):
    banal_click(Key.__getattr__(f'f{person_to_repair}'))
    for item in range(1, sizes[person_to_repair]+1):
        if item == 10:
            banal_click(Key.down)
        post_item = item if item<10 else item-9
        banal_click(f'{post_item}')
        banal_click('f')
        banal_click('y', 0.3)

Now: why did I need the hardcoded amount of items for each character? Because if I try to repair an item that doesn't exist, the script will get stuck (I'll get the message "Fix which item" that the script can't see, and I'll need to enter a digit).
This game would be easy to automate almost completely - because of the discrete nature of all actions - if one could get some response from the game that could be processed like a plain text.
 

KeighnMcDeath

RPG Codex Boomer
Joined
Nov 23, 2016
Messages
13,062
Were you using those dead mercs as backpacks? It has been awhile since I messed with III.
 

Dorateen

Arcane
Joined
Aug 30, 2012
Messages
4,370
Location
The Crystal Mist Mountains
The Might & Magic III discussion is very interesting. Thirty years ago, the Thanksgiving holiday fell on November 25, 1993 and I was in the middle of playing Isles of Terra. I found the old notebook I had used to record the adventure, and here is a page from that day.

CBCmvpY.jpg


I always loved how much random information M&M throws at the player during exploration, giving hints of what might be found in later areas.
 

Mauman

Learned
Joined
Jun 30, 2021
Messages
935
The Might & Magic III discussion is very interesting. Thirty years ago, the Thanksgiving holiday fell on November 25, 1993 and I was in the middle of playing Isles of Terra. I found the old notebook I had used to record the adventure, and here is a page from that day.

CBCmvpY.jpg


I always loved how much random information M&M throws at the player during exploration, giving hints of what might be found in later areas.
Reminds me of the big giant binder me and my brother kept when we were playing mm2 together.
 

solemgar

Educated
Patron
Joined
Aug 3, 2023
Messages
146
Location
Mechanus
Codex+ Now Streaming!
I like the script part. How did you write them?
This is an example of the actual script - the one I used for buffing:
Python:
from pynput.keyboard import Key, Controller
import time

SLEEP_BEFORE_START = 3
SLEEP_TIMES = {
        'movement': 0.15,
        'yes no': 0.2,
        'regular spell': 0.6,
        'altar change location': 8,
        'teleport no location change' : 1.2,
        'teleport change location': 6
}
SORCERER_POSITION = 5
CLERIC_POSITION = 4

SPELL_POSITION_SORCERER = {
        'teleport' : 21,
        'power shield' : 16,
}

SPELL_POSITION_CLERIC = {
        'blessed': 14,
        'holy bonus': 15,
        'heroism': 17
}

keyboard = Controller()

def banal_click(to_press, time_sleep = SLEEP_TIMES['movement']):
    keyboard.press(to_press)
    keyboard.release(to_press)
    time.sleep(time_sleep)

def move_forward(amount):
    to_press = Key.up
    for x in range(amount):
        banal_click(to_press)

def spell(person=None, spell_number=-1, additional = (), post_wait = SLEEP_TIMES['regular spell']):
    spell_button = 'c'
    banal_click(spell_button)
    if person:
        to_press = Key.__getattr__(f'f{person}')
        banal_click(to_press)

    if spell_number >= 0:
        banal_click('n')
        for x in range(spell_number-10):
            banal_click(Key.down)
        if spell_number >= 10:
            banal_click('0')
        else:
            banal_click(spell_number)
        banal_click('s')

    banal_click(spell_button)
    for button in additional:
        banal_click(button)
    time.sleep(post_wait)


def turn_left():
    banal_click(Key.left)

def turn_right():
    banal_click(Key.right)

def yes():
    banal_click('y', SLEEP_TIMES['yes no'])

def no():
    banal_click('n', SLEEP_TIMES['yes no'])

def spell_buffing():
    for spell_number in [SPELL_POSITION_CLERIC[_] for _ in ('blessed', 'holy bonus', 'heroism')]:
        first_time = False
        for key in [Key.f1, Key.f2]:
            spell(person=CLERIC_POSITION, spell_number=-1 if first_time else spell_number, additional = (key,), post_wait=SLEEP_TIMES['regular spell']) #Spellcaster's Buffs (No protection from elements
            first_time = True

    time.sleep(1)
    first_time = False
    for key in [Key.__getattr__(f'f{_}') for _ in range(1, 7)]:
        spell(person=SORCERER_POSITION, spell_number=-1 if first_time else SPELL_POSITION_SORCERER['power shield'], additional = (key,), post_wait=SLEEP_TIMES['regular spell']) #Spellcaster's Buffs (No protection from elements
        first_time = True

def write(txt):
    for _ in txt:
        banal_click(_)
    banal_click(Key.enter)

def to_the_well():
    turn_right()
    turn_right()
    spell(SORCERER_POSITION, SPELL_POSITION_SORCERER['teleport'], ('4', Key.enter), SLEEP_TIMES['teleport no location change'])
    turn_right()
    spell(SORCERER_POSITION, additional = ('9', Key.enter), post_wait = SLEEP_TIMES['teleport change location'])
    spell(SORCERER_POSITION, additional = ('5', Key.enter), post_wait = SLEEP_TIMES['teleport no location change'])
    spell(SORCERER_POSITION, additional = ('9', Key.enter), post_wait = SLEEP_TIMES['teleport change location'])
    spell(SORCERER_POSITION, additional = ('9', Key.enter), post_wait = SLEEP_TIMES['teleport no location change'])
    turn_right()
    yes()
    yes()
    yes()

def sequencer(*args):
    for x in args:
        if type(x) == int:
            move_forward(x)
        if x == 'l':
            turn_left()
        if x == 'r':
            turn_right()
        if type(x) == tuple and x[0] == 's':
            spell(**x[1])
        if type(x) == str and x[0] == 'y': #yes + amount of times to execute it
          amount = 1
          if len(x) > 0:
              amount = int(x[1:])
          for _ in range(amount):
              yes()

        if x == 'n':
            no()
        if x=='t': #turn around
            turn_right()
            turn_right()

def resistances_to_well():
    sequencer('t', 1, 'l', 4, 'r', 1, 'y1')
    time.sleep(1)
    write('air')
    time.sleep(SLEEP_TIMES['altar change location'])
    to_the_well()

time.sleep(SLEEP_BEFORE_START)
# Start: face North, (14, 6) - Blistering Heights (location after Town Portal / Box use)
spell_buffing()
time.sleep(2)
sequencer(2, 'l', 3, 'y2', 4, 'n', 4, 'y2', 't', 4, 'n', 'l', 4, #Here - elemental resistances
       'y2', 't', 4, 'n', 5, 'y2')
time.sleep(2)
resistances_to_well()

Note that I have to start at a certain place ((14, 6) - Blistering Heights) facing north. SLEEP_BEFORE_START determines the time I need to switch context to a game - the only thing this script does is pressing buttons and waiting. It's probably possible to send keys directly to the process, but I don't think it would be very portable. All the sleeping times were subjected to tinkering.
Now, obviously, this code is not very polished. I started by writing something like
Python:
from pynput.keyboard import Key, Controller
import time
keyboard = Controller()

time.sleep(3)
keyboard.press(Key.up)
keyboard.release(Key.up)
time.sleep(0.1)
keyboard.press(Key.up)
keyboard.release(Key.up)
time.sleep(0.1)

And then gradually moved all the repeating parts into functions, and some repeating hardcoded variables into constants. There are some Python hacks - like using __getattr__ to get an attribute of the Key class from a string or dictionary unpacking (**some_list) to easily pass a dictionary as a list of arguments to a function - but you can avoid them (albeit the code will be even less concise).
The only visible and obvious problems are the fact that I need to start facing the exact direction and know the position of a spell in a list of each character; the lack of feedback gets more frustrating when it comes to repair:
Python:
from pynput.keyboard import Key, Controller
import time

TIME_SLEEP = 0.15
keyboard = Controller()
def banal_click(to_press, time_sleep = TIME_SLEEP):
    keyboard.press(to_press)
    keyboard.release(to_press)
    time.sleep(time_sleep)

sizes = [-1, 17, 0, 17, 0, 0, 16] # This fixes 17 first items of the person under F1, 0 from person under F2 etc. -1 starts the list here, because F0 doesn't exist, and indexing in python starts from 0.

time.sleep(3)
for person_to_repair in range(1, 7):
    banal_click(Key.__getattr__(f'f{person_to_repair}'))
    for item in range(1, sizes[person_to_repair]+1):
        if item == 10:
            banal_click(Key.down)
        post_item = item if item<10 else item-9
        banal_click(f'{post_item}')
        banal_click('f')
        banal_click('y', 0.3)

Now: why did I need the hardcoded amount of items for each character? Because if I try to repair an item that doesn't exist, the script will get stuck (I'll get the message "Fix which item" that the script can't see, and I'll need to enter a digit).
This game would be easy to automate almost completely - because of the discrete nature of all actions - if one could get some response from the game that could be processed like a plain text.
Awesome! But how do you send the keys to the actual process once it gets the focus ? Or the script just runs in the background arbitrarily pressing keys?

I think something like this would be wonders for my Ishar playthrough in 86box
 

behold_a_man

Educated
Joined
Nov 26, 2022
Messages
144
But how do you send the keys to the actual process once it gets the focus ? Or the script just runs in the background arbitrarily pressing keys?
All I do is execute the script (either from the command line or in any other way), switch the focus (I've got SLEEP_BEFORE_START seconds - set to 3 here) to the game (by clicking on its window), and... that's it.
The script acts exactly as if I was pressing the keys. In the current implementation, I can't change the focus while the script executes - this would require some magic with finding certain processes for the banal_click function, I don't know whether the pynput module allows that, and it probably wouldn't be portable (I ran this game on Wine under Linux).

And, by the way - deleting a team member overwrites the last save - so I recommend backing up your saves in this game.
 

As an Amazon Associate, rpgcodex.net earns from qualifying purchases.
Back
Top Bottom