Adding Oangband magic realms/spellbooks. What changes do I need to make?

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Pete Mack
    Prophet
    • Apr 2007
    • 6883

    #61
    That isn't the problem. The trouble is (!a)|| b is not the same as !(a || b). You effectively wrote the former because ! has higher precedence than ||, so it will apply to a single term unless you put the expression inside parens.

    Comment

    • Elfin Jedi
      Adept
      • Mar 2013
      • 102

      #62
      Thanks! That helped. Now it works.

      /* Exclude monsters that are invisible or out of range */
      if (!(rf_has(mon->race->flags, RF_INVISIBLE ||
      mon->m_timed[MON_TMD_INVISIBLE]) ||
      mflag_has(mon->mflag, MFLAG_UNAWARE)))
      {

      Does this look right?

      Comment

      • Pete Mack
        Prophet
        • Apr 2007
        • 6883

        #63
        That looks good.

        Comment

        • Elfin Jedi
          Adept
          • Mar 2013
          • 102

          #64
          Ok, now that that is working... How do I do this?

          Originally posted by Pete Mack
          You need to mark the square with the memory moss for display update when an event like that happens.
          There are some parts of effects.c that look similar to what I think I need, is that where I would update it?

          Comment

          • Elfin Jedi
            Adept
            • Mar 2013
            • 102

            #65
            Would an edited version of this do the trick?

            /**
            * Monster self-healing.
            */
            bool effect_handler_MON_HEAL_HP(effect_handler_context_ t *context)
            {
            int midx = cave->mon_current;
            int amount = effect_calculate_value(context, FALSE);
            struct monster *mon = midx > 0 ? cave_monster(cave, midx) : NULL;
            char m_name[80], m_poss[80];
            bool seen;

            if (!mon) return TRUE;

            /* Get the monster name (or "it") */
            monster_desc(m_name, sizeof(m_name), mon, MDESC_STANDARD);

            /* Get the monster possessive ("his"/"her"/"its") */
            monster_desc(m_poss, sizeof(m_poss), mon, MDESC_PRO_VIS | MDESC_POSS);

            seen = (!player->timed[TMD_BLIND] && mflag_has(mon->mflag, MFLAG_VISIBLE));

            /* Heal some */
            mon->hp += amount;

            /* Fully healed */
            if (mon->hp >= mon->maxhp) {
            mon->hp = mon->maxhp;

            if (seen)
            msg("%s looks REALLY healthy!", m_name);
            else
            msg("%s sounds REALLY healthy!", m_name);
            } else if (seen) { /* Partially healed */
            msg("%s looks healthier.", m_name);
            } else {
            msg("%s sounds healthier.", m_name);
            }

            /* Redraw (later) if needed */
            if (player->upkeep->health_who == mon)
            player->upkeep->redraw |= (PR_HEALTH);

            /* Cancel fear */
            if (mon->m_timed[MON_TMD_FEAR]) {
            mon_clear_timed(mon, MON_TMD_FEAR, MON_TMD_FLG_NOMESSAGE, FALSE);
            msg("%s recovers %s courage.", m_name, m_poss);
            }

            return TRUE;
            }

            Comment

            • Elfin Jedi
              Adept
              • Mar 2013
              • 102

              #66
              bool effect_handler_MON_TIMED_INC:INVISIBLE(effect_hand ler_context_t *context)
              {
              int midx = cave->mon_current;
              int amount = effect_calculate_value(context, FALSE);
              struct monster *mon = midx > 0 ? cave_monster(cave, midx) : NULL;
              char m_name[80], m_poss[80];
              bool seen;

              if (!mon) return TRUE;

              /* Get the monster name (or "it") */
              monster_desc(m_name, sizeof(m_name), mon, MDESC_STANDARD);

              /* Get the monster possessive ("his"/"her"/"its") */
              monster_desc(m_poss, sizeof(m_poss), mon, MDESC_PRO_VIS | MDESC_POSS);

              seen = (!player->timed[TMD_BLIND] && mflag_has(mon->mflag, MFLAG_VISIBLE));

              I get stuck here though...

              something like: if monster has MON_TIMED_INC:INVISIBLE lose (mon->mflag, MFLAG_VISIBLE) and then redraw something?

              Comment

              • Pete Mack
                Prophet
                • Apr 2007
                • 6883

                #67
                Not quite. There is a special function for doing that kind of thing, called update_mon in mon-utils.c. You need to update the function to do the right thing with the invisibility flag, and call it when the monster uses the spell. You also need to call it when the timer goes to zero. So the spell should be essentially :
                Set the flag to the new timed value
                call the function
                return.
                It should not mess with seen at all. Just say "{The monster} calls a cloak of darkness about it/him/her" and call the function.

                It's important to fix it here, because this update_mon gets called every time the monster moves, and it is where the monster is determined to be visible or not.

                Edit: The function update_mon is called a "Listener" in computer science, that it is listens to "events" that affect some object. If angband were a newer product, this kind of thing would happen automatically every time the monster changed (via "accessor functions" on the monster.) The update_mon would never be called directly. Instead there would be a tiny function that updates the m_timed values and calls any listener(s). (There already is such a function for the player timed values.)

                https://en.wikipedia.org/wiki/Event_(computing)
                Last edited by Pete Mack; July 16, 2016, 05:38.

                Comment

                • Elfin Jedi
                  Adept
                  • Mar 2013
                  • 102

                  #68
                  It looks like I already updated this part some:

                  /* Learn about invisibility */
                  rf_on(lore->flags, RF_INVISIBLE);

                  /* Handle "invisible" monsters */
                  if (rf_has(mon->race->flags, RF_INVISIBLE || mon->m_timed[MON_TMD_INVISIBLE]) ) {
                  /* See invisible */
                  if (player_of_has(player, OF_SEE_INVIS))
                  {
                  /* Easy to see */
                  easy = flag = TRUE;
                  }

                  Edit: Do I put the spell beneath the "Learn about invisibility" section?

                  Comment

                  • Pete Mack
                    Prophet
                    • Apr 2007
                    • 6883

                    #69
                    This looks good. You just need to call the function from the spell, and when the timer goes to zero.

                    Comment

                    • Elfin Jedi
                      Adept
                      • Mar 2013
                      • 102

                      #70
                      Ok, I don't really know how to do that, but I wrote this (I don't know if I am on the right track):

                      "if (mon_has(mon->m_timed[MON_TMD_INVISIBLE])
                      "

                      Do I need to tell it to give the monster mon->m_timed[MON_TMD_INVISIBLE] or does this (from monster-spell.txt):

                      "name:INVISIBLE
                      hit:100
                      effect:MON_TIMED_INC:INVISIBLE
                      dice:50
                      power:40
                      lore:make self invisible
                      message-vis:{name} calls a cloak of darkness about {pronoun} body."

                      do that?

                      (I put the message you gave into the text file)

                      Edit: I am trying to figure out as much as possible on my own. But all I've ever done with programming before was make a program that made a window and then drew random shapes all over it one at a time, and that was years ago.

                      Comment

                      • Elfin Jedi
                        Adept
                        • Mar 2013
                        • 102

                        #71
                        Oh, and Nick (I saw you were on the thread), the spell realms work now except for displaying the book names in inventory (and store inventory) lists. I can't say the same for the individual spells yet.

                        (Right now I am working on something else though.)

                        Comment

                        • takkaria
                          Veteran
                          • Apr 2007
                          • 1951

                          #72
                          OK, so when you write effect:MON_TIMED_INC:INVISIBLE in the edit file, that means that the effect MON_TIMED_INC gets called with the parameter MON_TMD_INVISIBLE in context->p1. You don't have to write a function called effect_handler_MON_TIMED_INC:INVISIBLE to handle it.

                          The handler for MON_TIMED_INC is pretty simple, it just calls the code in mon-timed.c.

                          If you look in mon-timed.c, you can see that this the code handles printing the messages when monsters become/stop being invisible. It all happens in mon_set_timed(); see the variable m_note and the call to add_monster_message(). Those extra lines you added to list-mon-timed.h and list-mon-message.h make this all work. This will be in addition to the message you've set in the monster spell file.

                          What Pete said about calling update_mon() still stands, but you'd want to add a call in mon_set_timed() so when the invisiblily timed effect changes you call it.

                          In this bit:

                          Code:
                              if (resisted)
                                  m_note = MON_MSG_UNAFFECTED;
                              else
                                  mon->m_timed[ef_idx] = timer;
                          
                              if (player->upkeep->health_who == mon)
                                  player->upkeep->redraw |= (PR_HEALTH);
                          
                              /* Update the visuals, as appropriate. */
                              player->upkeep->redraw |= (PR_MONLIST);
                          You'd want to insert something like:

                          Code:
                          if (ef_idx == MON_TMD_INVISIBLE) {
                              update_mon(mon, cave, false);
                          }
                          And in mon_resist_effect() (also in mon-timed.c), which says whether a monster can resist an effect or not, you a line near the top saying

                          Code:
                          if (ef_idx == MON_TMD_INVISIBLE) return (false);
                          So that you don't end up with monsters resisting their own spell!

                          Originally posted by Elfin Jedi
                          It looks like I already updated this part some:

                          Code:
                          	/* Learn about invisibility */
                          	rf_on(lore->flags, RF_INVISIBLE);
                          
                          	/* Handle "invisible" monsters */
                          	if (rf_has(mon->race->flags, RF_INVISIBLE || mon->m_timed[MON_TMD_INVISIBLE])  ) {
                          		/* See invisible */
                          		if (player_of_has(player, OF_SEE_INVIS))
                          		{
                          			/* Easy to see */
                          			easy = flag = TRUE;
                          		}
                          Note that here you've put the || inside the rf_has() call instead of outside it. It should be

                          Code:
                          if (rf_has(mon->race->flags, RF_INVISIBLE) || mon->m_timed[MON_TMD_INVISIBLE])
                          Otherwise it looks fine.
                          takkaria whispers something about options. -more-

                          Comment

                          • Cold_Heart
                            Adept
                            • Mar 2012
                            • 141

                            #73
                            Originally posted by Nick
                            Thanks for all the updates. Ideally a whole new school of magic should be addable by the edit files
                            But spells still would need a C implementation? Unless you have something like very interesting new edit files + Lua or some such in mind.

                            Comment

                            • takkaria
                              Veteran
                              • Apr 2007
                              • 1951

                              #74
                              Originally posted by Cold_Heart
                              But spells still would need a C implementation? Unless you have something like very interesting new edit files + Lua or some such in mind.
                              See https://github.com/angband/angband/b...data/class.txt for an example of how spells are defined in the edit files now. Obviously if you want to invent brand new stuff you'll have to hack on C but you can do a lot lot in the edit files now.
                              takkaria whispers something about options. -more-

                              Comment

                              • Elfin Jedi
                                Adept
                                • Mar 2013
                                • 102

                                #75
                                Ok, I did this:

                                /* Determine if the monster resisted or not, if appropriate */
                                if (check_resist)
                                resisted = mon_resist_effect(mon, ef_idx, timer, flag);

                                if (ef_idx == MON_TMD_INVISIBLE) return (false);

                                if (resisted)
                                m_note = MON_MSG_UNAFFECTED;
                                else
                                mon->m_timed[ef_idx] = timer;

                                if (player->upkeep->health_who == mon)
                                player->upkeep->redraw |= (PR_HEALTH);

                                if (ef_idx == MON_TMD_INVISIBLE) {
                                update_mon(mon, cave, false);
                                }

                                And changed the parentheses.

                                I really don't know how to do this though:

                                Set the flag to the new timed value
                                call the function
                                return.

                                Comment

                                Working...
                                😀
                                😂
                                🥰
                                😘
                                🤢
                                😎
                                😞
                                😡
                                👍
                                👎