Angband Forums

Angband Forums (http://angband.oook.cz/forum/index.php)
-   Development (http://angband.oook.cz/forum/forumdisplay.php?f=10)
-   -   Vanilla Code Questions (http://angband.oook.cz/forum/showthread.php?t=9905)

DavidMedley March 16, 2020 01:57

Vanilla Code Questions
 
I'm hacking around with vanilla at the moment. I'm going to post some questions as they come up.

My background: I don't have a lot of experience with C but I have 15+ years experience as a professional software developer. I'm more familiar with Perl than any other language.

DavidMedley March 16, 2020 02:15

Where do things like PLAYER_LEVEL from class.txt get interpreted? I only find that string in text files and player-spell.c.
Code:

expression_base_value_f spell_value_base_by_name(const char *name)
{
        static const struct value_base_s {
                const char *name;
                expression_base_value_f function;
        } value_bases[] = {
                { "SPELL_POWER", spell_value_base_spell_power },
                { "PLAYER_LEVEL", spell_value_base_player_level },
                { "DUNGEON_LEVEL", spell_value_base_dungeon_level },
                { "MAX_SIGHT", spell_value_base_max_sight },
                { "WEAPON_DAMAGE", spell_value_base_weapon_damage },
                { "PLAYER_HP", spell_value_base_player_hp },
                { "MONSTER_PERCENT_HP_GONE", spell_value_base_monster_percent_hp_gone },
                { NULL, NULL },
        };
        const struct value_base_s *current = value_bases;

        while (current->name != NULL && current->function != NULL) {
                if (my_stricmp(name, current->name) == 0)
                        return current->function;

                current++;
        }

        return NULL;
}

When I saw this I thought "Jackpot!" But when I try to put in things like WEAPON_DAMAGE into class.txt, angband gives me a parse error when I run it. I tried PLAYER_HP and DUNGEON_LEVEL as well and they give the same error, though MONSTER_PERCENT_HP_GONE obviously works since it's part of the Necro class.

So where are these codes, such as PLAYER_LEVEL and MONSTER_PERCENT_HP_GONE interpretted?

DavidMedley March 16, 2020 02:29

Confirming: "s32b" means "signed 32 bit integer"? Example:
Code:

        s32b new_mana, new_mana_frac;
If so, why use this construction instead of "signed long int"? Or just "long" for brevity?

wobbly March 16, 2020 04:54

Quote:

Originally Posted by DavidMedley (Post 143649)
Where do things like PLAYER_LEVEL from class.txt get interpreted? I only find that string in text files and player-spell.c.
Code:

expression_base_value_f spell_value_base_by_name(const char *name)
{
        static const struct value_base_s {
                const char *name;
                expression_base_value_f function;
        } value_bases[] = {
                { "SPELL_POWER", spell_value_base_spell_power },
                { "PLAYER_LEVEL", spell_value_base_player_level },
                { "DUNGEON_LEVEL", spell_value_base_dungeon_level },
                { "MAX_SIGHT", spell_value_base_max_sight },
                { "WEAPON_DAMAGE", spell_value_base_weapon_damage },
                { "PLAYER_HP", spell_value_base_player_hp },
                { "MONSTER_PERCENT_HP_GONE", spell_value_base_monster_percent_hp_gone },
                { NULL, NULL },
        };
        const struct value_base_s *current = value_bases;

        while (current->name != NULL && current->function != NULL) {
                if (my_stricmp(name, current->name) == 0)
                        return current->function;

                current++;
        }

        return NULL;
}

When I saw this I thought "Jackpot!" But when I try to put in things like WEAPON_DAMAGE into class.txt, angband gives me a parse error when I run it. I tried PLAYER_HP and DUNGEON_LEVEL as well and they give the same error, though MONSTER_PERCENT_HP_GONE obviously works since it's part of the Necro class.

So where are these codes, such as PLAYER_LEVEL and MONSTER_PERCENT_HP_GONE interpretted?

look in init.c for Initialize player classes

backwardsEric March 16, 2020 05:41

Quote:

Originally Posted by DavidMedley (Post 143650)
Confirming: "s32b" means "signed 32 bit integer"? Example:
Code:

        s32b new_mana, new_mana_frac;
If so, why use this construction instead of "signed long int"? Or just "long" for brevity?

Yes, it means a 32-bit signed integer. If one uses long, you don't have a guarantee about the size. For instance, when compiling 64-bit applications on Linux or Mac OS, a long is a 64-bit signed integer. There's a standard way of referring to integers with a known number of bits (int32_t, uint32_t, ....), and you'll see that used in h-basic.h to define what s32b is. But those types were introduced after Angband was originally written, and it's understandable that Angband adopted its own convention.

wobbly March 16, 2020 05:52

Quote:

Originally Posted by DavidMedley (Post 143649)
When I saw this I thought "Jackpot!" But when I try to put in things like WEAPON_DAMAGE into class.txt, angband gives me a parse error when I run it. I tried PLAYER_HP and DUNGEON_LEVEL as well and they give the same error, though MONSTER_PERCENT_HP_GONE obviously works since it's part of the Necro class.

Changing:

Code:

spell:Magic Missile:1:1:22:4
effect:BOLT_OR_BEAM:MISSILE:0:-10
dice:$Dd4
expr:D:PLAYER_LEVEL:- 1 / 5 + 3
desc:Fires a magic missile that always hits its target and does
desc: unresistable damage.
desc:  Sometimes a beam is fired instead that hurts each monster
desc: in its path.
desc:  The chance to get a beam goes up with your character level.

to

Code:

spell:Magic Missile:1:1:22:4
effect:BOLT_OR_BEAM:MISSILE:0:-10
dice:$Dd4
expr:D:WEAPON_DAMAGE:- 1 / 5 + 3
desc:Fires a magic missile that always hits its target and does
desc: unresistable damage.
desc:  Sometimes a beam is fired instead that hurts each monster
desc: in its path.
desc:  The chance to get a beam goes up with your character level.

is working for me, & gives me a magic missile damage based on the dice of my weapon.

What parser error are you getting?

DavidMedley March 16, 2020 06:38

Quote:

Originally Posted by wobbly (Post 143660)
is working for me

Hmm ok
Code:

expr:D:WEAPON_DAMAGE: #<--doesn't parse
expr:D:WEAPON_DAMAGE:+ 0 #<-- does parse

Thanks!

DavidMedley March 16, 2020 06:40

Quote:

Originally Posted by backwardsEric (Post 143659)
those types were introduced after Angband was originally written

Makes sense. Thanks, Eric!

DavidMedley March 16, 2020 06:43

Quote:

Originally Posted by wobbly (Post 143652)
look in init.c for Initialize player classes

OK. Now that we have the other thing figured out, hopefully I won't have to make any changes in here!

DavidMedley March 16, 2020 08:37

OK, this is a pretty big ask, but I'll put it out into the universe and see what happens.

I want to create a spell that includes a melee blow as one of its effects. I've looked at
Code:

static bool py_attack_real(struct player *p, struct loc grid, bool *fear)
/**Attack the monster at the given location with a single blow.*/

And that seems to be perfect for what I have in mind, so I shouldn't have to write a whole new attack sequence.

But when I look at
Code:

bool spell_cast(int spell_index, int dir) {
...
        effect_do(spell->effect, source_player(), NULL, ident, true, dir, beam, 0)
...
}

It's really abstract and hard to follow. This probably makes it very flexible and powerful and (I'm hoping) pretty easy to get it to do what I want.

So can anyone provide me with hints or examples of how to do this?

wobbly March 16, 2020 09:25

Well here's a start:

Code:

/**
 * Execute an effect chain.
 *
 * \param effect is the effect chain
 * \param origin is the origin of the effect (player, monster etc.)
 * \param obj    is the object making the effect happen (or NULL)
 * \param ident  will be updated if the effect is identifiable
 *              (NB: no effect ever sets *ident to false)
 * \param aware  indicates whether the player is aware of the effect already
 * \param dir    is the direction the effect will go in
 * \param beam  is the base chance out of 100 that a BOLT_OR_BEAM effect will beam
 * \param boost  is the extent to which skill surpasses difficulty, used as % boost. It
 *              ranges from 0 to 138.
 */
bool effect_do(struct effect *effect,
                struct source origin,
                struct object *obj,
                bool *ident,
                bool aware,
                int dir,
                int beam,
                int boost)


Nick March 16, 2020 10:09

I think you'll have to write an effect handler (see effects.c - there are a whole lot of them) which will need to call py_attack_real() for each monster you want to hit. To do this you'll need to make py_attack_real() callable from other files, which means adding its definition to player-attack.h and including player-attack.h in effects.c.

DavidMedley March 16, 2020 13:12

OK, thanks!

Pete Mack March 16, 2020 15:09

The reason things are so abstract now is that, while the code is somewhat harder to understand, it is much easier to add things. In the old days, you would need to modify:
* the parser
* at least one .h file
* the global spell list
* the config files

Now to add most spells all you need to change is a couple config (.txt) files and possibly a .h file. Your change requires new interpretation in-code, as you need to surface weapon attacks as a magic effect, so you need a new spell effect procedure.

DavidMedley March 16, 2020 22:10

Quote:

Originally Posted by Pete Mack (Post 143680)
while the code is somewhat harder to understand, it is much easier to add things.

Yeah, that's what I figured. Thanks!

DavidMedley March 16, 2020 22:23

Is there a faster way to check my C syntax than to try to make the whole project?

backwardsEric March 16, 2020 23:31

Quote:

Originally Posted by DavidMedley (Post 143689)
Is there a faster way to check my C syntax than to try to make the whole project?

Are you using Visual Studio (or some other IDE)? For that, I can't offer specific advice. If you're using the makefiles, then you could recompile just one or more of the files, say mon-attack.c and mon-blows.c, by running

Code:

make src/mon-attack.o src/mon-blows.o
in the top-level directory (i.e. for the source file you are interested in, replace the .c with .o). For Mac OS X, the equivalent would be running

Code:

make -f Makefile.osx mon-attack.o man-blows.o
in the src directory. The makefiles, however, should only rebuild what's necessary for a change. So, unless you modified a header file that's widely used, you won't be gaining much by specifically recompiling a handful of files.

DavidMedley March 17, 2020 01:45

Oh, OK. I tried cc and that was awful. I'll try this way, or not, since you say it won't help much anyway.

DavidMedley March 17, 2020 07:32

A bit off-topic, but when I was trying to trace incremental changes to HP and SP, I found that SP regenerates every turn, but HP regens only every fourth turn, except when resting and then the ratio is 2 to 1. I don't understand how or why this is happening. Maybe I screwed something up.

I don't want to track it down right now, but I couldn't help but wonder aloud about it.

DavidMedley March 19, 2020 09:39

Can someone explain the difference between power and mult in object_properties.txt?

# power: the value given to the property in object power calculations
# mult: relative value of properties, used in power calculations
# type-mult: extra multiplier used in power for particular properties on
# particular types of object. Assumed 1 if not mentioned

Nick March 19, 2020 09:51

Quote:

Originally Posted by DavidMedley (Post 143727)
Can someone explain the difference between power and mult in object_properties.txt?

Look in obj-power.c, mainly modifier_power() and flags_power().

DavidMedley March 19, 2020 10:22

Quote:

Originally Posted by Nick (Post 143728)
Look in obj-power.c, mainly modifier_power() and flags_power().

Can't you just do that for me, and write up a summary? Heh, j/k. Thanks for the direction.

DavidMedley March 19, 2020 10:27

I see these log statements in there. How do I turn those on?

Nick March 19, 2020 11:16

Quote:

Originally Posted by DavidMedley (Post 143730)
I see these log statements in there. How do I turn those on?

They're used when generating randarts. If you play a character with randarts, you'll get a (verbose!) randart.log file in your user directory which describes the randart generation process.

DavidMedley March 19, 2020 17:45

Quote:

Originally Posted by Nick (Post 143732)
They're used when generating randarts. If you play a character with randarts, you'll get a (verbose!) randart.log file in your user directory which describes the randart generation process.

I didn't get that file when I started a new randarts game :(

Nick March 19, 2020 20:27

Quote:

Originally Posted by DavidMedley (Post 143738)
I didn't get that file when I started a new randarts game :(

That's odd, I do. Anyone playing randarts - are you seeing a randart.log in your user directory? Please let me know OS and other details if so (or if not).

DavidMedley March 19, 2020 20:34

Quote:

Originally Posted by Nick (Post 143740)
Please let me know OS and other details

I'm compiling a modified version of the nightly on linux

Nick March 19, 2020 20:38

Quote:

Originally Posted by DavidMedley (Post 143741)
I'm compiling a modified version of the nightly on linux

So you're not seeing a ~/.angband/Angband/randart.log ?

DavidMedley March 19, 2020 20:43

Quote:

Originally Posted by Nick (Post 143742)
So you're not seeing a ~/.angband/Angband/randart.log ?

No, pretty sure I'm being thorough.

find | grep randart
./angband/src/obj-randart.o
./angband/src/obj-randart.c
./angband/src/obj-randart.h
./angband/src/list-randart-properties.h
./angband/lib/archive/randart_0e7ca6bf.txt

find | grep log
./angband/config.log
./angband/.git/logs
./angband/.git/logs/HEAD
./angband/.git/logs/refs
./angband/.git/logs/refs/remotes
./angband/.git/logs/refs/remotes/origin
./angband/.git/logs/refs/remotes/origin/HEAD
./angband/.git/logs/refs/heads
./angband/.git/logs/refs/heads/master

DavidMedley March 19, 2020 20:48

randart_0e7ca6bf.txt describes the artifacts but nothing about their creation

DavidMedley March 19, 2020 20:48

It's not a crucial issue

Nick March 19, 2020 20:54

It's your .angband directory, not your angband directory :)

DavidMedley March 19, 2020 21:44

Aha! I missed the tilde in your earlier post. Got it now. Thanks!

DavidMedley March 20, 2020 09:29

How do I get "player-flags:RAGE_FUEL" to not throw a parse error on startup?

Nick March 20, 2020 09:41

Quote:

Originally Posted by DavidMedley (Post 143761)
How do I get "player-flags:RAGE_FUEL" to not throw a parse error on startup?

It will need an entry in player_property.txt, and an entry in list-player-flags.h

DavidMedley March 20, 2020 09:47

I swear to God list-player-flags.h sprang into existence the moment you made this post through some vanilla maintainer sorcery

wobbly March 20, 2020 10:16

When I'm adding flags I use a search all files on a flag thats already there. So you can search know_zapper and all the relevent files will pop up. At least almost, it'll miss a couple like is_zapper for instance, but at least it'll find the list flags file you missed.

DavidMedley March 20, 2020 10:25

Yeah. I think I must have searched for an object flag -- probably IMPAIR_HP -- and that's why I wasn't finding what I needed.

DavidMedley March 20, 2020 11:33

Why is it so hard to keep my fork up to date? I've barely changed anything in github, and I could throw those few changes away. But when I try
Code:

damedley wants to merge 202 commits into damedley:master from angband:master
it's saying I have like a dozen files I have to manually merge. What gives? More to the point, how can I make it easy as possible to merge changes into my version, and request a pull into the real version?

DavidMedley March 20, 2020 12:22

Quote:

Originally Posted by DavidMedley (Post 143769)
it's saying I have like a dozen files I have to manually merge.

To clarify, these are changes that I have nothing to do with. Maybe they haven't been merged in the mainline version yet? And once they are it won't be an issue for me anymore?

wobbly March 20, 2020 13:32

You've done something funky. Some of the changes you're trying to pull in have been in master since September 2019

DavidMedley March 20, 2020 19:08

Quote:

Originally Posted by wobbly (Post 143776)
You've done something funky. Some of the changes you're trying to pull in have been in master since September 2019

Hmm ok thanks for the tip.

DavidMedley March 20, 2020 19:11

I guess I'll have to delete this and fork anew.

DavidMedley March 20, 2020 20:50

I think I'm on the right track with github now. Question: is there a git setting to avoid updating a bunch of lines where the only change is my editor auto-trimmed some trailing whitespace?

moosferatu March 20, 2020 23:33

If it's actually trimming spaces, you'll need to configure that in your editor.

What OS are you using? Windows? Most likely, it's converting line endings -- a highly irritating problem.

https://help.github.com/en/github/us...e-line-endings

DavidMedley March 21, 2020 02:14

It's not the newlines, but thanks. It's the odd extra space or tab.

Nick March 21, 2020 03:00

Here is my recommendation for managing your own version of the angband git repository:
  1. Fork the official repo (angband/angband) using the fork button on github
  2. Clone/download this to get your own local copy
  3. Keep your master branch up-to-date with the official master branch, do not do development work on your master branch
  4. For development work, create a branch and do your work there. Once it's ready for inclusion, push it to your github repo and make a pull request
  5. The official master branch will be updated frequently. Make sure that you (fairly frequently):
    • Pull changes from the official repo and update your master (it should be just a fast-forward, since you are not developing on your master);
    • Rebase your development branch or branches against your master branch, resolving any conflicts that arise

This is how I work, and it should keep confusion to a minimum.

DavidMedley March 21, 2020 04:17

OK, good tips. I know less about version control than I probably should.

DavidMedley March 23, 2020 20:37

I got my changes into a new branch, rolled my master back (via CLI couldn't find this option on github), and can now pull in the 13 commits at the press of a button. Github gives me 3 choices for this:
- Create a merge commit
- Squash and merge
- Rebase and merge

Which do you recommend?

Nick March 23, 2020 20:54

Quote:

Originally Posted by DavidMedley (Post 143826)
I got my changes into a new branch, rolled my master back (via CLI couldn't find this option on github), and can now pull in the 13 commits at the press of a button. Github gives me 3 choices for this:
- Create a merge commit
- Squash and merge
- Rebase and merge

Which do you recommend?

If you're pulling commits into your new branch from master and want to stay aligned with it, use rebase - that will bring your branch up to date with master, and then replay your new commits onto that base.

DavidMedley March 23, 2020 21:41

OK, maybe I'm doing it wrong. I thought the first step was to pull from angband:master to myband:master.

Nick March 23, 2020 22:41

OK, let's start again. Which 13 commits?

DavidMedley March 23, 2020 22:46

Heh, sorry. I need to read a book :-(

I have a master branch that is exactly like the master branch from Mar 17, 2020. From there I created a BGmod branch, and all my changes are in there. Then I tried this https://github.com/damedley/myband/pull/1 "damedley wants to merge 13 commits into damedley:master from angband:master". And that's where I paused, pondering the merge/squash/rebase choice.

Nick March 23, 2020 22:49

Quote:

Originally Posted by DavidMedley (Post 143832)
Heh, sorry. I need to read a book :-(

I have a master branch that is exactly like the master branch from Mar 17, 2020. From there I created a BGmod branch, and all my changes are in there. Then I tried this https://github.com/damedley/myband/pull/1 "damedley wants to merge 13 commits into damedley:master from angband:master". And that's where I paused, pondering the merge/squash/rebase choice.

Right, so I would recommend using CLI to do that, although it may be that rebase and merge would work.

DavidMedley March 23, 2020 22:56

Via which command?

Nick March 23, 2020 23:51

Quote:

Originally Posted by DavidMedley (Post 143834)
Via which command?

I do
Code:

git fetch official
git merge official/master

on my master branch.

DavidMedley March 26, 2020 00:49

Having Trouble with Timed Resistance
 
I tried adding a timed free action effect. I copied everywhere I saw confusion or att_conf. It compiles and runs. When cast, it gives the message I wrote. The notice shows at the bottom. The flag is set in the character sheet. But when something tries to slow or paralyze the character it simply doesn't work. Can anyone suggest why this might be?

Nick March 26, 2020 00:57

Quote:

Originally Posted by DavidMedley (Post 143889)
I tried adding a timed free action effect. I copied everywhere I saw confusion or att_conf. It compiles and runs. When cast, it gives the message I wrote. The notice shows at the bottom. The flag is set in the character sheet. But when something tries to slow or paralyze the character it simply doesn't work. Can anyone suggest why this might be?

In calc_bonuses() in payer-calcs.c you will see a bunch of special cases like this for timed effects, for example
Code:

        if (p->timed[TMD_SINVIS]) {
                of_on(state->flags, OF_SEE_INVIS);
        }

You will need a similar thing for your timed free action.

DavidMedley March 26, 2020 01:26

Do you see anything wrong with this?

Code:

        if (p->timed[TMD_FREE_ACT]) {
                of_on(state->flags, OF_FREE_ACT);
        }


Nick March 26, 2020 01:36

Quote:

Originally Posted by DavidMedley (Post 143892)
Do you see anything wrong with this?

Code:

        if (p->timed[TMD_FREE_ACT]) {
                of_on(state->flags, OF_FREE_ACT);
        }


Looks perfect.

DavidMedley March 26, 2020 03:19

That's what I already did, but it didn't work. :( Thanks.

Nick March 26, 2020 03:38

Quote:

Originally Posted by DavidMedley (Post 143896)
That's what I already did, but it didn't work. :( Thanks.

Hard to guess exactly where it's failing, but player_inc_check() in player-timed.c is a good place to start.

wobbly March 26, 2020 06:54

You could push it to your repository where it'd be easier to see if you've done something strange?

DavidMedley March 26, 2020 15:44

I think I missed updating something. I made sure all my changes were present, recompiled, and it worked. I'm still a bit baffled how everything the user can see said it was working, but it didn't. Doesn't matter for now. Sorry for the false alarm.

DavidMedley March 26, 2020 22:48

Is there an easy way to specify KILL_WALL to be adjacent only?

DavidMedley March 27, 2020 00:02

Melee_blows
 
Finally wrote my first effect handler. I really don't understand the code too well, but copy and paste served me surprisingly well. Only bug I'm aware of is it crashes if there's not an enemy to use it on. This obviously needs to be fixed. Anything else anyone sees? I'm not confident in the target and grid stuff.

Code:

bool effect_handler_MELEE_BLOWS(effect_handler_context_t *context)
{
        int blows = effect_calculate_value(context, false);
        bool fear;
        int taim;
        struct loc target = loc(-1, -1);
        struct loc grid = player->grid;

/* players only for now */
        if (context->origin.what != SRC_PLAYER)
                return false;

        /* Ask for a target if no direction given */
        if (context->dir == DIR_TARGET && target_okay()) {
                target_get(&target);
        } else {
                target = loc_sum(player->grid, ddgrid[context->dir]);
        }

        taim = distance(grid, target);
        if (taim > 1) {
                msgt(MSG_GENERIC, "Distance to target %d", taim);
                return false;
        }

        while (blows-- > 0) {
                if(py_attack_real(player, target, &fear)) {return true;}
        }
        return true;
}


Nick March 27, 2020 01:16

Quote:

Originally Posted by DavidMedley (Post 143937)
Is there an easy way to specify KILL_WALL to be adjacent only?

I think you probably want the project_touch() function in effects.c.

I don't see anything obviously wrong with your effect handler; I'm guessing the most likely source of problems is whether py_attack_real() plays nicely with being called in this way.

DavidMedley March 29, 2020 20:35

In player-calcs.c
Code:

if (player_has(p, PF_EVIL) && character_dungeon) {
what does character_dungeon mean?

Nick March 29, 2020 21:25

Quote:

Originally Posted by DavidMedley (Post 144010)
In player-calcs.c
Code:

if (player_has(p, PF_EVIL) && character_dungeon) {
what does character_dungeon mean?

It's a hackish global variable that is set to true when a level has been generated and then to false when generation for a new level starts. It gets used quite a bit to enable calculations in the birth process when you don't really have a character but want to pretend you have.

DavidMedley March 31, 2020 18:05

Compiling For Windows
 
Is compiling for Windows pretty easy? I followed the instructions. The compile fails and I'm told I need windows.h, but I'm sure the list doesn't end there. Am I supposed to grab standard windows libraries until the compile goes through?

wobbly March 31, 2020 18:15

What are you using to compile? I use MINGW & I just edit makefile.win adding the line

MINGW=yes

then I type:

make -f makefile.win

& that's it. (except when it throws compiler errors)

DavidMedley March 31, 2020 18:20

I just followed these instructions on linux:
Code:

./autogen.sh
./configure --enable-win --disable-curses --build=i686-pc-linux-gnu --host=i586-mingw32msvc


DavidMedley April 1, 2020 15:44

When you're testing and want to advance a character in experience (through debug commands), how do you balance equipment? Any rules of thumb?

DavidMedley April 1, 2020 16:01

Quote:

Originally Posted by wobbly (Post 144067)
What are you using to compile? I use MINGW & I just edit makefile.win adding the line

MINGW=yes

then I type:

make -f makefile.win

& that's it. (except when it throws compiler errors)

I wasn't able to follow these directions. The closest I could find was src/Makefile.win . But I get errors like this:
Code:

/bin/bash: no: command not found
Makefile:31: recipe for target 'win/angband.res' failed

My knowledge of compiling C is close to zero :(

Sideways April 1, 2020 17:03

Quote:

Originally Posted by DavidMedley (Post 144093)
When you're testing and want to advance a character in experience (through debug commands), how do you balance equipment? Any rules of thumb?

For testing monster balance, the ideal is to just have a real character of the appropriate level, put aside for testing purposes. (You don't necessarily need to have that many of them - one early-game @, one or two midgame @s and one endgame @ will go a really long way.)

If you're testing character balance (e.g. on a new class or a heavily modified one) there's really no shortcuts, you have to play a real @ to know if it's good, or somehow convince a bunch of other people to do it for you :)

If you're testing things unrelated to monster/character balance you generally don't need to worry about niceties like equipment; and if you're testing monsters of really high level and don't have a real endgame character at hand you can just put together a random kit of oppy artifacts.

DavidMedley April 1, 2020 17:49

Quote:

Originally Posted by Nick (Post 143784)
Here is my recommendation for managing your own version of the angband git repository:
  1. Fork the official repo (angband/angband) using the fork button on github
  2. Clone/download this to get your own local copy
  3. Keep your master branch up-to-date with the official master branch, do not do development work on your master branch
  4. For development work, create a branch and do your work there. Once it's ready for inclusion, push it to your github repo and make a pull request
  5. The official master branch will be updated frequently. Make sure that you (fairly frequently):
    • Pull changes from the official repo and update your master (it should be just a fast-forward, since you are not developing on your master);
    • Rebase your development branch or branches against your master branch, resolving any conflicts that arise

This is how I work, and it should keep confusion to a minimum.

I did some much overdue study on git. The above directions helped me a lot. I think the main step I was missing, and maybe should have been in these directions, was to add the original fork to my list of remotes:
Code:

git remote add official https://github.com/angband/angband.git
After that it was pretty smooth sailing.

DavidMedley April 1, 2020 17:51

Thanks for the advice, Sideways!

DavidMedley April 1, 2020 21:14

I don't understand these errors.

Code:

                from player.c:19:
player-attack.h:46:55: warning: ‘struct player’ declared inside parameter list will not be visible outside of this definition or declaration
 typedef struct attack_result (*ranged_attack) (struct player *p,
                                                      ^~~~~~
player-attack.h:56:38: warning: ‘struct player’ declared inside parameter list will not be visible outside of this definition or declaration
 int chance_of_melee_hit(const struct player *p, const struct object *weapon);
                                      ^~~~~~
player-attack.h:59:30: warning: ‘struct player’ declared inside parameter list will not be visible outside of this definition or declaration
 extern void py_attack(struct player *p, struct loc grid);
                              ^~~~~~
player-attack.h:60:35: warning: ‘struct player’ declared inside parameter list will not be visible outside of this definition or declaration
 extern bool py_attack_real(struct player *p, struct loc grid, bool *fear);
                                  ^~~~~~
Successfully compiled player.c.

My "BGmod" branch on Github is up to date now, if that helps.
https://github.com/damedley/myband/b...d/src/player.c

backwardsEric April 1, 2020 22:48

Quote:

Originally Posted by DavidMedley (Post 144106)
I don't understand these errors.

Code:

                from player.c:19:
player-attack.h:46:55: warning: ‘struct player’ declared inside
parameter list will not be visible outside of this definition or declaration
 typedef struct attack_result (*ranged_attack) (struct player *p,
                                                      ^~~~~~
...
Successfully compiled player.c.


Those are the first references to struct player that it saw in that compilation unit: effects.h is your first include file in player.c and neither it nor the files it pulls in bring in player.h. You could include player.h in player-attack.h or you could add a forward declaration of struct player to player-attack.h. The latter is just a way of introducing the name but doesn't provide a full declaration; it would look like

Code:

struct player;
and you'd put it in player-attack.h before you mention struct player in the typedefs or function prototypes.

DavidMedley April 2, 2020 00:59

Yeah, that all makes sense. I guess the real question is: how did I introduce this warning, when I haven't touched player-attack.h, other than to add:
Code:

extern bool py_attack_real(struct player *p, struct loc grid, bool *fear);
But that's probably something I have to figure out for myself.

Pete Mack April 2, 2020 01:15

That reference to player IS the reason. If you first include player.h instead of picking it up later, the warning will vanish. But a forward declaration is better:

strict player;

...
Reference to *player. You only need the full structure when you dereference the pointer (with * or ->), and that never happens in .h files.

DavidMedley April 2, 2020 19:09

Who gets credit for this?
Code:

const s16b ddd[9] =
{ 2, 8, 6, 4, 3, 1, 9, 7, 5 };

Or:
Code:

7 1 6
3 5 2
5 0 4


Pete Mack April 2, 2020 19:46

Not sure about what the second bit is, but the first part--the list of directions to allow iterating loops--is old, old code.

Quote:

Originally Posted by DavidMedley (Post 144125)
Who gets credit for this?
Code:

const s16b ddd[9] =
{ 2, 8, 6, 4, 3, 1, 9, 7, 5 };

Or:
Code:

7 1 6
3 5 2
5 0 4



DavidMedley April 2, 2020 19:54

The second part is arranging it like you would on a numpad. 4 -> down and to the right, for example.

DavidMedley April 7, 2020 16:14

Found this interesting bit:
#define PY_KNOW_LEVEL 30 /* Level to know all runes */

But it doesn't appear to be in use. Does this mean someone intended all runes to be instantly known at character level 30? If this constant isn't used again, shouldn't it throw a compiler warning?

DavidMedley April 7, 2020 19:55

Code:

/**
 * Return the player's chance to hit with a particular weapon.
 */
int chance_of_melee_hit(const struct player *p, const struct object *weapon)
{
        int chance, bonus = p->state.to_h;

        if (weapon)
                bonus += weapon->to_h;
        chance = p->state.skills[SKILL_TO_HIT_MELEE] + bonus * BTH_PLUS_ADJ;
        return chance;
}

/* elsewhere */
#define BTH_PLUS_ADJ            3                /* Adjust BTH per plus-to-hit */

So a +1 to hit is equivalent to 3 skill points, right? So a warrior that starts with 70 melee skill effectively has +11 to-hit over a rogue who starts with 35, for example. (They both advance at the same rate.)

Pete Mack April 7, 2020 20:53

No. The 3x applies to the to_h bonus on the character sheet, sum of effects from equipment, stats, and buffs.

wobbly April 7, 2020 21:27

I'm failing to see the difference. 35 + 11 * 3 is well not exactly 70 but pretty close & if you look at how it displays on the character sheet:

human warrior: to-hit: 24,
human rogue: to-hit: 13,

Nick April 7, 2020 22:42

Quote:

Originally Posted by DavidMedley (Post 144294)
Found this interesting bit:
#define PY_KNOW_LEVEL 30 /* Level to know all runes */

But it doesn't appear to be in use. Does this mean someone intended all runes to be instantly known at character level 30? If this constant isn't used again, shouldn't it throw a compiler warning?

IIRC there was a plan for that to happen at some time during the development of rune ID, but it was decided not to be necessary. And I think the compiler doesn't throw an error because it's not in actual code, it's just the preprocessor.

DavidMedley April 9, 2020 01:33

Coming back to compiling for Windows... Any help is greatly appreciated because I have no idea what I'm doing.

Instructions:
Quote:

Cross-building for Windows with Mingw
Many developers (as well as the auto-builder) build Angband for Windows using Mingw on Linux. This requires that the necessary Mingw packages are all installed.

This type of build now also uses autotools, so you must configure it to cross-compile, e.g.:

./autogen.sh
./configure --enable-win --disable-curses --build=i686-pc-linux-gnu --host=i586-mingw32msvc
./autogen.sh
Code:

*info* running aclocal (-I m4)
*info* running autoheader
*info* running autoconf

./configure --enable-win --disable-curses --build=i686-pc-linux-gnu --host=i586-mingw32msvc
Code:

checking build system type... i686-pc-linux-gnu
checking host system type... i586-pc-mingw32msvc
checking target system type... i586-pc-mingw32msvc
checking for tput... /usr/bin/tput
configure: touching .deps files
Note: You have chosen to compile for installation, with data files
    in standard locations. For development, you may wish to consider using
    --with-no-install which will leave the game to run from the directory
    into which it was extracted and compiled.

checking for i586-mingw32msvc-gcc... no
checking for gcc... gcc
configure: WARNING: using cross tools not prefixed with host triplet
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... yes
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking whether make sets $(MAKE)... yes
checking whether ln -s works... yes
checking for a BSD-compatible install... /usr/bin/install -c
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for i586-mingw32msvc-windres... no
checking for windres... no
checking for rst2html.py... no
checking for rst2html... no
checking for rst2latex.py... no
checking for rst2latex... no
checking for pdflatex... no
checking for rm... /bin/rm
checking for mv... /bin/mv
checking for cp... /bin/cp
checking for dirent.h that defines DIR... yes
checking for library containing opendir... none required
checking how to run the C preprocessor... gcc -E
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking fcntl.h usability... yes
checking fcntl.h presence... yes
checking for fcntl.h... yes
checking for stdint.h... (cached) yes
checking for stdbool.h that conforms to C99... yes
checking for _Bool... yes
checking for an ANSI C-conforming const... yes
checking return type of signal handlers... void
checking for mkdir... yes
checking for setresgid... yes
checking for setegid... yes
checking for stat... yes
checking if gcc supports -Wno-missing-field-initializers... yes
checking if make supports SysV-style inclusion... yes
checking for make silent include syntax... gnu
checking for mvwaddnwstr... no
checking for use_default_colors... no
checking for can_change_color... no
checking for X... no
configure: creating ./config.status
config.status: creating mk/buildsys.mk
config.status: creating mk/extra.mk
config.status: creating mk/sinclude.mk
config.status: creating src/autoconf.h

Configuration:

  Install path:                          /usr/local
  binary path:                            /usr/local/games
  config path:                            /usr/local/etc/angband/
  lib path:                              /usr/local/share/angband/
  doc path:                              /usr/local/share/doc/angband/
  var path:                              (not used)
  (with private save and score files in ~/.angband/Angband/)

-- Frontends --
- Curses                                  Disabled
- X11                                    No; missing libraries
- SDL2                                    Disabled
- SDL                                    Disabled
- Windows                                Yes
- Test                                    No
- Stats                                  No

- SDL2 sound                              Disabled
- SDL sound                              Disabled

make
Code:

Entering directory src.
win/readpng.c:21:10: fatal error: windows.h: No such file or directory
 #include <windows.h>
          ^~~~~~~~~~~
compilation terminated.
win/scrnshot.c:19:10: fatal error: windows.h: No such file or directory
 #include <windows.h>
          ^~~~~~~~~~~
compilation terminated.
win/win-layout.c:19:10: fatal error: windows.h: No such file or directory
 #include <windows.h>
          ^~~~~~~~~~~
compilation terminated.
Successfully generated dependencies.
/bin/bash: no: command not found
Makefile:31: recipe for target 'win/angband.res' failed
make[3]: *** [win/angband.res] Error 127
../mk/buildsys.mk:110: recipe for target 'all' failed
make[2]: *** [all] Error 2
mk/buildsys.mk:115: recipe for target 'subdirs' failed
make[1]: *** [subdirs] Error 2
mk/buildsys.mk:110: recipe for target 'all' failed
make: *** [all] Error 2


backwardsEric April 9, 2020 01:51

Quote:

Originally Posted by DavidMedley (Post 144366)
Code:

checking for i586-mingw32msvc-gcc... no
checking for gcc... gcc
configure: WARNING: using cross tools not prefixed with host triplet


Someone with more experience will likely chime in, but from that message, it used gcc rather than i586-mingw32msvc-gcc as the compiler. If that's the gcc targeting Linux (which would depend on what your path is), then that would explain why it couldn't find windows.h.

Is the mingw executable directory in your path?

DavidMedley April 9, 2020 02:34

Yeah, that makes a lot of sense. Seems obvious now that you say it. I'll try again later.

moosferatu April 9, 2020 02:49

I don't know what OS you're using, but I was able to build it just now by doing the following on Fedora:

Code:

sudo dnf install mingw32-binutils mingw32-gcc
./configure --enable-win --disable-curses --build=i686-pc-linux-gnu --host=i686-w64-mingw32
make

As the Angband compile instructions say, the value of --host is system dependent. The easiest way to check what that value should be, if yours is different, is just through tab completion. You should have a command like i686-w64-mingw32-gcc on your path.

DavidMedley April 9, 2020 03:33

OK good stuff. Thanks.

DavidMedley June 1, 2020 19:15

I'm back! :-D

In effects.c effect_handler_MOVE_ATTACK function I wrote a while ago:

Code:

        /* Ask for a target */
        if ((context->dir == DIR_TARGET) && target_okay()) {
                target_get(&target);
        }

        /* Should only target known/visible? */
        if (square_monster(cave, target) == NULL) {
                msg("This spell must target a monster.");
                return false;
        }

I thought this would allow you to press an direction key and if there's an adjacent monster there, the target would be set and pass the "must target a monster" test. But it doesn't. Any hints here?

Nick June 1, 2020 21:43

Quote:

Originally Posted by DavidMedley (Post 145968)
I'm back! :-D

In effects.c effect_handler_MOVE_ATTACK function I wrote a while ago:

Code:

        /* Ask for a target */
        if ((context->dir == DIR_TARGET) && target_okay()) {
                target_get(&target);
        }

        /* Should only target known/visible? */
        if (square_monster(cave, target) == NULL) {
                msg("This spell must target a monster.");
                return false;
        }

I thought this would allow you to press an direction key and if there's an adjacent monster there, the target would be set and pass the "must target a monster" test. But it doesn't. Any hints here?

You don't need the second code block. That code is designed to make sure the player has actually formally targeted a monster, and can't just use a direction, as in the Command spell, for example - so it stops precisely what you want to happen.

Sideways June 1, 2020 21:55

Nick can correct me if I'm wrong, since I'm by no means familiar with V's targetting code, but it looks to me like the first code block would specifically handle the situation in which the player specified a target location rather than a target direction (since DIR_TARGET is 5); that part should work, but only if you want to accept location targetting in addition to direction targetting, and only if there's code elsewhere for handling a direction target. (I don't see any such code in effect_handler_MOVE_ATTACK.)

DavidMedley June 2, 2020 02:00

OK, that DIR_TARGET is 5 bit helped. New code seems to work:

Code:

        if (context->dir == DIR_TARGET) {
                target_get(&target);
        }
        else {
                target = loc_sum(player->grid, ddgrid[context->dir]);
        }
        /* Should only target known/visible? */
        if (square_monster(cave, target) == NULL) {
                msg("This spell must target a monster.");
                return false;
        }


DavidMedley June 2, 2020 03:10

Does monster_is_visible return true if you are aware of the monster through ESP, detection, etc? If not, is there something that does? Sorry, being a bit lazy right now because I'm in a rush.

EDIT: monster_is_in_view, monster_is_visible, monster_is_obvious look like the leading candidates.

Nick June 2, 2020 03:26

Quote:

Originally Posted by DavidMedley (Post 145981)
Does monster_is_visible return true if you are aware of the monster through ESP, detection, etc? If not, is there something that does? Sorry, being a bit lazy right now because I'm in a rush.

EDIT: monster_is_in_view, monster_is_visible, monster_is_obvious look like the leading candidates.

monster_is_visible is the one you want - it corresponds to what is drawn on the screen. Unless you want to rule out mimics, in which case use monster_is_obvious.

And don't panic too much :)


All times are GMT +1. The time now is 11:07.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, vBulletin Solutions Inc.