About player and the chat info

Developers
brucelei
2007-04-03
2013-06-06
  • brucelei
    brucelei
    2007-04-03

    Hi!
    When player say something,the chat info will show in the game,but when player moved,the chat info is still in the old position.
    I want to let the chat info follow with player,how can I do this?

     
    • Hi,

      Not sure it is an easy change...
      You would need to modify the Text entity to has a link to the player that created it, so each time you draw the entity you get the x,y value from the player that created the entity instead of the text entity itself.

       
    • brucelei
      brucelei
      2007-04-10

      Thanks for your advice,Miguel!We have implemented this just like what you say.

      Now I have made some new change on the portal,when we click the portal,the player will move to the portal and enter automaticly.
      I have modified games.stendhal.client.gui.wt.GroundContainer,added some code in the onMouseClick() method:

      **************************************************************
      //destination point
      int px = (int) point.getX();
      int py = (int) point.getY();

      if (entity!=null && entity.getType().equals("portal") ){
          // move player and use portal action
          RPAction action = new RPAction();
          action.put("type", "moveanduse");
          action.put("x", px);
          action.put("y", py);
          int id = entity.getID().getObjectID();
          action.put("target", id);
          StendhalClient.get().send(action);
      }
      **************************************************************

      Then register "moveanduse" action with class games.stendhal.server.actions.MoveAndUseAction,it's full source code:

      /* $Id: MoveAndUseAction.java,v 1.7 2007/04/10 16:00:31 nhnb Exp $ */
      /***************************************************************************
      *                      (C) Copyright 2003 - Marauroa                      *
      ***************************************************************************
      ***************************************************************************
      *                                                                         *
      *   This program is free software; you can redistribute it and/or modify  *
      *   it under the terms of the GNU General Public License as published by  *
      *   the Free Software Foundation; either version 2 of the License, or     *
      *   (at your option) any later version.                                   *
      *                                                                         *
      ***************************************************************************/
      package games.stendhal.server.actions;

      import org.apache.log4j.Logger;

      import marauroa.common.game.*;
      import games.stendhal.client.StendhalClient;
      import games.stendhal.client.entity.Entity;
      import games.stendhal.common.*;
      import games.stendhal.server.*;
      import games.stendhal.server.entity.item.Item;
      import games.stendhal.server.entity.player.Player;
      import games.stendhal.server.events.UseListener;
      import games.stendhal.server.pathfinder.Path;

      import java.util.List;
      import java.util.ArrayList;

      import marauroa.common.Log4J;

      public class MoveAndUseAction extends ActionListener {
          private static final Logger logger = Log4J.getLogger(MoveAction.class);

          public static void register() {
              MoveAndUseAction moveanduse = new MoveAndUseAction();
              StendhalRPRuleProcessor.register("moveanduse", moveanduse);
          }

          @Override
          public void onAction(Player player, RPAction action) {
              Log4J.startMethod(logger, "moveanduse");

              String type = action.get("type");

              moveanduse(player, action);
          }

          private void moveanduse(Player player, RPAction action) {
              Log4J.startMethod(logger, "moveanduse");

              int x = 0, y = 0, playerX = 0, playerY = 0;
              //The flag of move
              boolean needMove = true;

              if (player.hasPath()) {
                  player.clearPath();
              }

              if (action.has("x") && action.has("y")) {
                  x = action.getInt("x");
                  y = action.getInt("y");
                  playerX = player.getX();
                  playerY = player.getY();
                 
                  //if player is closer to portal,then he needn't to move
                  if (player.nextTo(x, y, 0.25)){
                      needMove = false;
                  }           
                 
                  if (needMove){
                      //According to the player and portal's pos,combine the 8 points closer to portal
                      //The closest point is in the first
                      ArrayList<Path.Node> destPoints = new ArrayList<Path.Node>();
                      if (playerX < x) {
                          if (playerY < y) {
                              destPoints.add(new Path.Node(x - 1, y - 1));
                              destPoints.add(new Path.Node(x - 1, y));
                              destPoints.add(new Path.Node(x, y - 1));
                              destPoints.add(new Path.Node(x - 1, y + 1));
                              destPoints.add(new Path.Node(x + 1, y - 1));
                              destPoints.add(new Path.Node(x, y + 1));                       
                              destPoints.add(new Path.Node(x + 1, y));
                              destPoints.add(new Path.Node(x + 1, y + 1));
                          } else if (playerY == y) {
                              destPoints.add(new Path.Node(x - 1, y));
                              destPoints.add(new Path.Node(x - 1, y - 1));
                              destPoints.add(new Path.Node(x - 1, y + 1));
                              destPoints.add(new Path.Node(x, y - 1));
                              destPoints.add(new Path.Node(x, y + 1));
                              destPoints.add(new Path.Node(x + 1, y - 1));
                              destPoints.add(new Path.Node(x + 1, y + 1));
                              destPoints.add(new Path.Node(x + 1, y));
                          } else {
                              destPoints.add(new Path.Node(x - 1, y + 1));
                              destPoints.add(new Path.Node(x, y + 1));
                              destPoints.add(new Path.Node(x - 1, y));
                              destPoints.add(new Path.Node(x + 1, y + 1));
                              destPoints.add(new Path.Node(x - 1, y - 1));
                              destPoints.add(new Path.Node(x + 1, y));
                              destPoints.add(new Path.Node(x, y - 1));
                              destPoints.add(new Path.Node(x + 1, y - 1));
                          }
                      } else if (playerX == x) {
                          if (playerY < y) {
                              destPoints.add(new Path.Node(x, y - 1));
                              destPoints.add(new Path.Node(x - 1, y - 1));
                              destPoints.add(new Path.Node(x + 1, y - 1));
                              destPoints.add(new Path.Node(x - 1, y));
                              destPoints.add(new Path.Node(x + 1, y));
                              destPoints.add(new Path.Node(x - 1, y + 1));
                              destPoints.add(new Path.Node(x + 1, y + 1));
                              destPoints.add(new Path.Node(x, y + 1));
                          } else if (playerY > y) {
                              destPoints.add(new Path.Node(x, y + 1));
                              destPoints.add(new Path.Node(x - 1, y + 1));
                              destPoints.add(new Path.Node(x + 1, y + 1));
                              destPoints.add(new Path.Node(x - 1, y));
                              destPoints.add(new Path.Node(x + 1, y));
                              destPoints.add(new Path.Node(x - 1, y - 1));
                              destPoints.add(new Path.Node(x + 1, y - 1));
                              destPoints.add(new Path.Node(x, y - 1));
                          }
                      } else {
                          if (playerY < y) {
                              destPoints.add(new Path.Node(x + 1, y - 1));
                              destPoints.add(new Path.Node(x, y - 1));
                              destPoints.add(new Path.Node(x + 1, y));
                              destPoints.add(new Path.Node(x + 1, y + 1));
                              destPoints.add(new Path.Node(x - 1, y - 1));
                              destPoints.add(new Path.Node(x, y + 1));
                              destPoints.add(new Path.Node(x - 1, y));
                              destPoints.add(new Path.Node(x - 1, y + 1));
                          } else if (playerY == y) {
                              destPoints.add(new Path.Node(x + 1, y));
                              destPoints.add(new Path.Node(x + 1, y - 1));
                              destPoints.add(new Path.Node(x + 1, y + 1));
                              destPoints.add(new Path.Node(x, y - 1));
                              destPoints.add(new Path.Node(x, y + 1));
                              destPoints.add(new Path.Node(x - 1, y - 1));
                              destPoints.add(new Path.Node(x - 1, y + 1));
                              destPoints.add(new Path.Node(x - 1, y));
                          } else {
                              destPoints.add(new Path.Node(x + 1, y + 1));
                              destPoints.add(new Path.Node(x + 1, y));
                              destPoints.add(new Path.Node(x, y + 1));
                              destPoints.add(new Path.Node(x + 1, y - 1));
                              destPoints.add(new Path.Node(x - 1, y - 1));
                              destPoints.add(new Path.Node(x - 1, y));
                              destPoints.add(new Path.Node(x, y - 1));
                              destPoints.add(new Path.Node(x - 1, y - 1));
                          }
                      }
                     
                      // Find the point which is closet and can use portal
                      for (int i = 0; i < destPoints.size(); i++) {
                          Path.Node node = destPoints.get(i);
                          List<Path.Node> path = Path.searchPath(player, node.x, node.y - 2);
                          if (path.size() > 0) {
                              player.setPath(path, false);
                              break;
                          }
                      }
                  }
         
                  //apply move
                  player.applyClientDirection(false);
              }

              //apply the thread which checking player can use portal or not
              int usedObject = action.getInt("target");
              new UsePortal(player, x, y, usedObject).start();

              Log4J.finishMethod(logger, "moveanduse");
          }
      }

      class UsePortal extends Thread {
          Player player;

          int x = 0, y = 0, usedObject = 0;

          int count = 0;

          public UsePortal(Player player, int x, int y, int usedObject) {
              this.player = player;
              this.x = x;
              this.y = y;
              this.usedObject = usedObject;
          }

          public void run() {
              boolean forbid = true;
              while (forbid) {
                  try {
                      if (Math.abs(player.getX() - x) > 1 || Math.abs(player.getY() - y) > 2) {
                          sleep(200);
                      } else {
                          //Here, check if the 3 point under portal can pass or not,if can't then sleep
                          if ((Math.abs(player.getX() - x) <= 1
                                  && (player.getY() - y == 1 || player.getY() - y == 2))){
                              sleep(200);
                          }
                          else{
                              forbid = false;
         
                              StendhalRPZone zone = (StendhalRPZone) StendhalRPWorld.get().getRPZone(player.getID());
                              RPObject.ID targetid = new RPObject.ID(usedObject, zone.getID());
                              if (zone.has(targetid)) {
                                  RPObject object = zone.get(targetid);
                                  invokeUseListener(player, object);
                              }
                          }
                      }
                  } catch (Exception ex) {
                  }
              }
          }

          private void invokeUseListener(Player player, RPObject object) {

              // HACK: No item transfer in jail (we don't want a jailed player to
              //       use items like home scroll.
              String zonename = StendhalRPWorld.get().getRPZone(player.getID()).getID().getID();
              if ((object instanceof Item) && (zonename.endsWith("_jail"))) {
                  player.sendPrivateText("For security reasons items may not be used in jail.");
                  return;
              }

              String name = object.get("type");
              if (object.has("name")) {
                  name = object.get("name");
              }
              String infostring = "";
              if (object.has("infostring")) {
                  infostring = object.get("infostring");
              }

              StendhalRPRuleProcessor.get().addGameEvent(player.getName(), "use", name, infostring);
              if (object instanceof UseListener) {
                  UseListener item = (UseListener) object;
                  item.onUsed(player);
                  return;
              }
          }
      }
      **************************************************************

      Now,it works,but I am not sure this is the best way,and when I debug MoveAndUseAction,the server got a fatal error,but only once:
      **************************************************************
      175343 FATAL marauroa.server.game.RPServerManager  - Unhandled exception, server
      will shut down.
      java.util.ConcurrentModificationException
              at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(Unknown Source)
              at java.util.LinkedHashMap$ValueIterator.next(Unknown Source)
              at marauroa.server.game.MarauroaRPZone.reset(MarauroaRPZone.java:202)
              at marauroa.server.game.MarauroaRPZone.nextTurn(MarauroaRPZone.java:218)

              at marauroa.server.game.RPWorld.nextTurn(RPWorld.java:194)
              at marauroa.server.game.RPServerManager.run(RPServerManager.java:505)
      **************************************************************
      So I am not sure the error is related with my own thread,do you have better advice?
      Thank you!

      PS:How can I upload attach file in this forum?The content above is too long,excuse me:-)

       
      • Well, the problem is because of the thread.
        IMHO using a thread is not an good idea, think about a way of not using the thread.

        The problem is that your thread is accessing the RPWorld ( that is not thread safe ) without any control.

        My best bet is to remove the thread and do in another way.

         
        • brucelei
          brucelei
          2007-04-11

          But if we remove the thread,I can't image other ways to realtime processing the job of checking player is closer to portal or not.
          At the present time,I am not very familiar with the code architecture of arianne.
          Can you give me some hints?Thank you!

          Regards,BruceLei!

           
          • Sure, sorry.

            Well, in fact to check if player is near a portal can be done at client, yes?
            So using a thread a client won't be as bad.

            Anyway, to do it server side, we do in the next way.
            Have a list of tasks to do, add the check player near portal to the list and on each turn check it ( very fast, so remove the sleep )

            The turntime spirit is seriously deep in marauroa/stendhal so you can't just make threads to do game oriented stuff ( unless you have very clear what you want to do and manage to sync correctly )

             
    • brucelei
      brucelei
      2007-04-11

      OK,That's fine,I have tried the first method to implement this,everything is ok!

      Speak to the second method,I am not very clear to the mechanism of the tasks implement  between two turns,if you have time,can you illustrate that more?Maybe list the primary classes will be helpful for me:)

      Finally,thanks for your help these days,I'll continue to explore arianne,and I hope can join the develop team in the future,I'll try my best to do something and be persistent,hope you can give some advice,thank you!

      Regards,BruceLei!

       
      • Ok, for example...
        Have a look at how attack works.
        Attack is something that last more than one turn.
        Make sandwidchs, grow grain fields, etc... are also things that last more than one turn.
        That code may be more illustrative than any example I can thought of now.

         
    • Daniel Herding
      Daniel Herding
      2007-04-13

      What are your experiences with text bubbles that follow players? I could imagine it is very hard to read a text bubble that keeps moving around.

       
      • brucelei
        brucelei
        2007-04-13

        Ha,we have combined HPbar and Text.

        First,modify method RenderingPipeline.draw(GameScreen screen),comment the line:
        //gameObjects.drawText(screen);

        Then in method RPEntity.drawHPbar(screen),draw text and HPbar together.
        When player say something,the chat info will display and move with HPbar,if over the display time,text will be removed,like the original mode:)

         
        • Yes, but as wikipedian pointed I see little point on the text going with you. (IMHO)
          What other thinks?

           
          • brucelei
            brucelei
            2007-04-16

            Ok,I'll show more details of my ideas:

            1. Modify Text.java,Add method:
            /* let text to be a son of player:-) */
            public void setFather(RPEntity father){
                this.father = father;
            }

            2. Modify RPEntity.java,manage text list,include textsToRemove:
            private List<Text> texts = new LinkedList<Text>();;
            private List<Text> textsToRemove = new LinkedList<Text>();
            public void addText(Text entity){
                texts.add(entity);
            }
            public void removeText(Text entity) {
                textsToRemove.add(entity);
            }
            public void removeAllText(){
                textsToRemove=texts;
            }

            3. In GameObjects.java,modify 2 addText() method,associate with player and text each other:
            try{
                entity.setFather((RPEntity)speaker);
                if (forwardText!=null){
                    ((RPEntity)objects.get(speaker.getID())).removeText(forwardText);
                }
                ((RPEntity)objects.get(speaker.getID())).addText(entity);
                forwardText=entity;
            }catch(Exception ex){
                ex.printStackTrace();
            }

            4. Modify method RPEntity.drawHPbar(),get the last element of texts,draw text and hpbar at the same time.

             


Anonymous


Cancel   Add attachments