Multiplayer Hub Logo  
  Powered by Noble Master Games, http://www.noblemaster.com Multiplayer Dragon
  Forums Twitter Dev. Blog ⊕  
Home > Forums

MultiplayerHub.com
» Forums|New Posts
» Twitter
» Dev. Blog
» About
» Contact Us
Showcase
» Age of Conquest
» Demise of Nations
» Retro Commander

































Multiplayer Forums


Board index » Games » Age of Conquest (AOC)


Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: More ideas from the bottom of the world...
PostPosted: 16 Jul 2017, 22:12 
Serf
Serf

Joined: 24 May 2017, 13:07
Posts: 19
I'll spare your the details regarding the continued state of cold in my lovely part of the world.

Ideas:

#1 A review system for modded maps - A way for players to rate the quality of the modded maps they play. Maybe and up down vote or a star scale system. This would allow map makers to see which maps the community enjoys the most. Also as we get more and more modded maps available it would be nice to be able to order their display by rating to avoid endless scrolling to get to the most played maps

#2 Changing the way random join games work. Currently when you join a game with the random nation setting it will show you as a nation. Many new players mistakenly believe this is the nation they have randomly been given for the game. They then conclude that by repeatedly disjoining and rejoining the game they can alter the nation they "randomly" will be playing. To avoid the constant pain of breaking aoc noobs dreams I suggest not showing players as specific nations when they join the game. Possibly just a message in the game chat saying "playername has joined the game." This is not a major issue but I guess there is room for potential improvement.

#3 Long game ai? This is more like a half formed idea I had so please let me know what you think. When we play long games that last for many weeks or months we all eventually come to a point where we will be unable to log in for a few days. This can very easily ruin our games and can also ruin the games for others. I suggest the development of a "manager" ai that we can activate the do simple tasks for us when we are away. The ai could be set to different modes such as "eco" where is simple grows you economy. Or defence where it responds to potential attacks... possibly also a combination of these two features. Obviously it shouldn't be able to launch major attacks.. or any attacks at all? I just thing a way to have our nations not completely inactive when we are away for a while might be cool.

Question:

Is there any way we can see the scripts that control ai actions? Id love to be able to see exactly what determines when an ai will attack, retreat, build ect.

Thanks. banana


Top
 Profile  
 
 Post subject: Re: More ideas from the bottom of the world...
PostPosted: 16 Jul 2017, 22:59 
Game Developer
Game Developer
User avatar

Joined: 17 Apr 2005, 02:34
Posts: 8077
Location: Honolulu
Quote:
#1 A review system for modded maps

It's already in there! Are you running a really old version of the game without the star-rating system?

Quote:
#2 Changing the way random join games work.

Put it onto the todo-list!

Quote:
#3 Long game ai?

A vacation mode/vacation AI was discussed before. It's on the todo-list but without a clear implementation plan.

Quote:
Is there any way we can see the scripts that control ai actions?
It's about 5000 lines of code distributed over several files. Not going to post all as it's little bit difficult to fully understand it without the rest of the code. Here are the first couple hundred lines of code:

Code:
    World world = controller.getWorld();
    Actor actor = controller.getActor();
    int actorIndex = world.getActorIndex(actor);
    Arena arena = world.getArena();

    boolean multiplayer = world.getHumanCount() >= 2;

    Matter matterCash = world.getMatterCash();
   
    int happinessBound = arena.getVariant().getHappinessBound();
    int happinessGood = happinessBound + 5;
    if (happinessGood > 100) {
      happinessGood = 100;
    }
   
    BalanceCash balanceCash = BalanceCash.create(world, actor);
    Balance[] balances = new Balance[world.getMatterCount()];
    for (int i = 0; i < world.getMatterCount(); i++) {
      Matter matter = world.getMatter(i);
      balances[i] = Balance.create(world, actor, matter);
    }
    Market market = arena.getMarket();
   
    AIMind mind = controller.getAIMind();
    AIMemo memo = controller.getAIMemo();
     
    // delete old dispatches
    int index = 0;
    while (index < actor.getDispatchs().getCount()) {
      Dispatch dispatch = actor.getDispatchs().get(index);
      if (dispatch.getTurn() < (world.getTurn().getTick() - 2)) {
        controller.getEntry().enterWorldDispatchDelete(dispatch);
        controller.getEntry().apply();
      }
      else {
        index++;
      }
    }
   
    // update notes, a.k.a. relations with other actors based on current relation
    Set<Actor> relationAggressors = new HashSet<Actor>(world.getActorCount() - 1);
    for (int i = 0; i < world.getActorCount(); i++) {
      Actor other = world.getActor(i);
      if ((other.isAlive()) && (!other.equals(actor))) {
        // still alive: keep a tab on all our relations (except ourself!)
        Note note = memo.getNote(other);
       
        // human?
        if (controller.getAI() == AI.INHUMAN) {
          if (!AI.hasAI(other.getUser())) {
            // we don't like humans! :-P
            if (memo.getRand().nextInt(3) == 0) {
              // we reduce their opinion every 3 turns in average
              note.setOpinion(note.getOpinion() - 2);
            }
          }
        }
       
        // if it's our group, then we are best friend :-D
        Group group = other.getGroup();
        if ((group != null) && (group.equals(actor.getGroup()))) {
          // our group: best friends :-D
          note.setOpinion(Integer.MAX_VALUE);
        }
        else {
          // enemy: update based on our relation!
          Relation relation = actor.getRelations().getRelation(other);
          switch (relation) {
            case NEUTRAL: {
              note.setOpinion(note.getOpinion() + mind.mainOpinionNeutral200());
              break;
            }
            case ALLIANCE: {
              note.setOpinion(note.getOpinion() + mind.mainOpinionAlliance200());
              break;
            }
            case AT_WAR: {
              note.setOpinion(note.getOpinion() + mind.mainOpinionAtWar200());

              if (note.hasConflictBegin()) {
                // not yet recorded: start tracking war!
                note.setConflictBegin(world.getTurn().getTick());
                note.setConflictBeginPotency(note.getPotency());
                note.setConflictBeginPotencySelf(memo.getPotency());
              }
              break;
            }
            case AT_PEACE: {
              note.setOpinion(note.getOpinion() + mind.mainOpinionAtPeace200());
              break;
            }
            case CEASE_FIRE: {
              note.setOpinion(note.getOpinion() + mind.mainOpinionCeaseFire200());
              break;
            }
            case PROTECTOR: {
              note.setOpinion(note.getOpinion() + mind.mainOpinionProtector200());
              break;
            }
            case PROTECTORATE: {
              note.setOpinion(note.getOpinion() + mind.mainOpinionProtectorate200());
              break;
            }
            default: {
              Log.e("Relation not implemented: " + relation);
            }
          }
         
          // enemy: update based on relations with others
          for (int k = 0; k < world.getActorCount(); k++) {
            Actor otherOther = world.getActor(k);
            if ((other != otherOther) && (actor != otherOther)) {
              if (other.getRelations().getRelation(otherOther) == Relation.AT_WAR) {
                if ((actor.getRelations().getRelation(otherOther) == Relation.ALLIANCE) ||
                    (actor.getRelations().getRelation(otherOther) == Relation.PROTECTORATE)) {
                  // take note of guy as an aggressor
                  relationAggressors.add(other);
                 
                  // this guy is at war with our ally or protectorate
                  note.setOpinion(note.getOpinion() + mind.mainOpinionAtWarWithAlly200());
                }
              }
            }
          }
        }
      }
    }   
   
    // update relations based on intrusions
    Set<Actor> intrusions = new HashSet<Actor>(2 * world.getActorCount());
    for (int i = 0; i < world.getPieceCount(); i++) {
      Piece piece = world.getPiece(i);
      if ((piece.hasCompMov()) && (piece.hasCompOwn())) {
        Actor owner = piece.getCompOwn().getOwner();
        if ((actor != owner) && (owner != null)) {
          // on our territory?
          if ((piece.getCompPos().hasPosition()) && (piece.getCompPos().getPosition().getOwner() == actor)) {
            Relation relation = actor.getRelations().getRelation(owner);
            if ((relation != Relation.ALLIANCE) && (relation != Relation.PROTECTOR)) {
              if (!intrusions.contains(owner)) {
                // new intrusion!
                intrusions.add(owner);

                // lower opinion
                Note note = memo.getNote(owner);
                note.setOpinion(note.getOpinion() + mind.mainOpinionIntrudor200());
              }
            }
          }
        }
      }
    }
   
    // update relations based on relationship changes!
    for (int i = 0; i < controller.getEntry().getEventCount(); i++) {
      Event event = controller.getEntry().getEvent(i);
      if (event instanceof EventInputWorldRelationCancel) {
        // relation cancelled - on us?
        EventInputWorldRelationCancel eventObject = (EventInputWorldRelationCancel)event;
        if (actor.equals(eventObject.getTarget(world))) {
          Note note = memo.getNote(eventObject.getSource(world));
          note.setOpinion(note.getOpinion() + mind.mainOpinionRelationCancel200());
        }
      }
      else if (event instanceof EventInputWorldRelationDeclarewar) {
        // war declared - on us?
        EventInputWorldRelationDeclarewar eventObject = (EventInputWorldRelationDeclarewar)event;
        if (actor.equals(eventObject.getTarget(world))) {
          Note note = memo.getNote(eventObject.getSource(world));
          note.setOpinion(note.getOpinion() + mind.mainOpinionRelationDeclarewar200());

          // start tracking war!
          note.setConflictBegin(world.getTurn().getTick());
          note.setConflictBeginPotency(note.getPotency());
          note.setConflictBeginPotencySelf(memo.getPotency());
        }       
      }
    }
   
    // update relations based on dispatches (e.g. money sent, diplo accepted/rejected!)
    for (int i = 0; i < actor.getDispatchs().getCount(); i++) {
      Dispatch dispatch = actor.getDispatchs().get(i);
      if ((dispatch.getTurn() == (world.getTurn().getTick() - 1)) && (dispatch.getTarget().equals(actor))) {
        if (dispatch instanceof Request) {
          // Request: let's see if there's something nice?
          Request request = (Request)dispatch;
          Request.Topic topic = request.getTopic();
          if (request.getState() == Request.State.REQUEST) {
            // it's a request (we just judge here - they are handled below!)!
            switch (topic) {
              case ALLIANCE: {
                // we don't change opinion
                break;
              }
              case PEACE: {
                // we don't change opinion
                break;
              }
              case SUBMIT_DEMAND: {
                // we don't like being asked to become a protectorate :-(
                Note note = memo.getNote(request.getSource());
                note.setOpinion(note.getOpinion() + mind.mainOpinionDemandSubmission200());
                break;
              }
              case SUBMIT_OFFER: {
                // we like that: more income through a protectorate :-D
                Note note = memo.getNote(request.getSource());
                note.setOpinion(note.getOpinion() + mind.mainOpinionOfferJoinLiege200());
                break;
              }
              case CEASE_FIRE_2: {
                // we don't change opinion
                break;
              }
              case CEASE_FIRE_3: {
                // we don't change opinion
                break;
              }
              case CEASE_FIRE_4: {
                // we don't change opinion
                break;
              }
              case CEASE_FIRE_5: {
                // we don't change opinion
                break;
              }
              case CEASE_FIRE_6: {
                // we don't change opinion
                break;
              }
              case CEASE_FIRE_7: {
                // we don't change opinion
                break;
              }
              case SUPPORT_OFFER: {
                // we got support :-D
                boolean doubleSupport = false;
                for (int k = 0; k < i; k++) {
                  Dispatch dispatch2 = actor.getDispatchs().get(k);
                  if ((dispatch2.getTurn() == (world.getTurn().getTick() - 1)) && (dispatch2.getTarget().equals(actor))) {
                    if (dispatch2 instanceof Request) {
                      Request request2 = (Request)dispatch2;
                      Request.Topic topic2 = request2.getTopic();
                      if ((request2.getState() == Request.State.REQUEST) && (topic2 == Request.Topic.SUPPORT_OFFER)) {
                        // sent support multiple times to gain favorable view - we will ignore :-P
                        doubleSupport = true;                       
                      }
                    }
                  }
                }
                if (!doubleSupport) {
                  // we count it as "nice" and basing the niceness on our own assets (relative size of "present")
                  Note note = memo.getNote(request.getSource());
                  Matter matter = request.getParam().getMatterSource();
                  int matterRevenue = Balance.create(world, actor, matter).getRevenueInternal();
                  int supportFactor = ((100 * request.getParam().getMatterSourceAmount()) / (matterRevenue > 0 ? matterRevenue : 1));
                  if (supportFactor > 100) {
                    // we maximum count 100% of what we would earn per turn!
                    supportFactor = 100;
                  }
                  note.setOpinion(note.getOpinion() + (supportFactor * mind.mainOpinionOfferSupport200() / 100));
                }
                break;
              }
              case SUPPORT_QUERY: {
                // we don't change opinion
                break;
              }
              case TRADE_CALL: {
                // determine if good/bad trade based on offset to market price!
                Note note = memo.getNote(request.getSource());
                Matter matter = request.getParam().getMatterTarget();
                int matterCount = request.getParam().getMatterTargetAmount();
                int matterPrice = (Market.ITEM_PRICE_FAC * request.getParam().getMatterSourceAmount()) / matterCount;
                int marketPrice = (market.getItemPrice(matter, false));
                if ((matterPrice * 2) < marketPrice) {
                  // very cheap buying offer :(
                  note.setOpinion(note.getOpinion() + mind.mainOpinionRequestTradeCallEvil200());
                }
                else if (matterPrice > (marketPrice * 2)) {
                  // very high buying offer :)
                  note.setOpinion(note.getOpinion() + mind.mainOpinionRequestTradeCallNice200());
                }
                break;
              }
              case TRADE_SELL: {
                // determine if good/bad trade based on offset to market price!
                Note note = memo.getNote(request.getSource());
                Matter matter = request.getParam().getMatterSource();
                int matterCount = request.getParam().getMatterSourceAmount();
                int matterPrice = (Market.ITEM_PRICE_FAC * request.getParam().getMatterTargetAmount()) / matterCount;
                int marketPrice = (market.getItemPrice(matter, true));
                if ((matterPrice * 2) < marketPrice) {
                  // very cheap sale :)
                  note.setOpinion(note.getOpinion() + mind.mainOpinionRequestTradeSellNice200());
                }
                else if (matterPrice > (marketPrice * 2)) {
                  // very expensive sale :(
                  note.setOpinion(note.getOpinion() + mind.mainOpinionRequestTradeSellEvil200());
                }
                break;
              }
              case PLACE_CALL: {
                // we don't change opinion
                break;
              }
              case PLACE_SELL: {
                // we don't change opinion
                break;
              }
              case JOIN_WAR: {
                // we don't change opinion
                break;
              }
              default: {
                Log.e("Cannot handle topic: " + topic);
              }
            }
          }
          else {
            // it's a response to a request from us!
            Note note = memo.getNote(request.getSource());
            int opinion = note.getOpinion();
            boolean accepted = request.getState() == Request.State.RESPONSE_ACCEPTED;
            switch (topic) {
              case ALLIANCE: {
                opinion += accepted ? mind.mainOpinionResponseAllianceAccept200() : mind.mainOpinionResponseAllianceReject200();   
                break;
              }
              case PEACE: {
                opinion += accepted ? mind.mainOpinionResponsePeaceAccept200() : mind.mainOpinionResponsePeaceReject200();   
                break;
              }
              case SUBMIT_DEMAND: {
                opinion += accepted ? mind.mainOpinionResponseSubmitDemandAccept200() : mind.mainOpinionResponseSubmitDemandReject200();   
                break;
              }
              case SUBMIT_OFFER: {
                opinion += accepted ? mind.mainOpinionResponseSubmitOfferAccept200() : mind.mainOpinionResponseSubmitOfferReject200();   
                break;
              }
              case CEASE_FIRE_2:
              case CEASE_FIRE_3:
              case CEASE_FIRE_4:
              case CEASE_FIRE_5:
              case CEASE_FIRE_6:
              case CEASE_FIRE_7:{
                opinion += accepted ? mind.mainOpinionResponseCeaseFireAccept200() : mind.mainOpinionResponseCeaseFireReject200();             
                break;
              }
              case SUPPORT_OFFER: {
                opinion += accepted ? mind.mainOpinionResponseSupportOfferAccept200() : mind.mainOpinionResponseSupportOfferReject200();   
                break;
              }
              case SUPPORT_QUERY: {
                opinion += accepted ? mind.mainOpinionResponseSupportQueryAccept200() : mind.mainOpinionResponseSupportQueryReject200();   
                break;
              }
              case TRADE_CALL: {
                opinion += accepted ? mind.mainOpinionResponseTradeAccept200() : mind.mainOpinionResponseTradeReject200();   
                break;
              }
              case TRADE_SELL: {
                opinion += accepted ? mind.mainOpinionResponseTradeAccept200() : mind.mainOpinionResponseTradeReject200();   
                break;
              }
              case PLACE_CALL: {
                // no option change
                break;
              }
              case PLACE_SELL: {
                // no option change
                break;
              }
              case JOIN_WAR: {
                opinion += accepted ? mind.mainOpinionResponseJoinWarAccept200() : mind.mainOpinionResponseJoinWarReject200();   
                break;
              }
              default: {
                Log.e("Cannot handle topic: " + topic);
              }
            }
            note.setOpinion(opinion);
          }
        }
      }
    }
   

_________________
play: Age of Conquest IV


Top
 Profile  
 
 Post subject: Re: More ideas from the bottom of the world...
PostPosted: 17 Jul 2017, 00:42 
Serf
Serf

Joined: 24 May 2017, 13:07
Posts: 19
Hi Noble thanks for that! I got the map review tool now! Yeah I reckon a "vacation mode" would be an awesome idea... probably needs a but more discussion. hmm defiantly some interesting features in that chunk of code you pasted there :D As a student I've spent countless hours battling my programming projects so I find it very interesting to see how you have gone about a project of this scale! If I were to give you my email address is there any chance you would be able to send me a more complete set of the files? Obviously I have 0 intention of reproducing anything from them but I do find it interesting both in terms of improving my play and in seeing some of the development decision you have made. Cheers.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
cron

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Green Smilies by http://www.greensmilies.com/

Home  |  Forums  |  Twitter  |  Dev. Blog  |  About  |  Contact