001package com.fs.starfarer.api.impl.campaign;
002
003import java.awt.Color;
004import java.util.ArrayList;
005import java.util.List;
006
007import com.fs.starfarer.api.Global;
008import com.fs.starfarer.api.campaign.CampaignFleetAPI;
009import com.fs.starfarer.api.campaign.FactionAPI;
010import com.fs.starfarer.api.campaign.RepLevel;
011import com.fs.starfarer.api.campaign.ReputationActionResponsePlugin;
012import com.fs.starfarer.api.campaign.SectorEntityToken;
013import com.fs.starfarer.api.campaign.TextPanelAPI;
014import com.fs.starfarer.api.campaign.comm.CommMessageAPI;
015import com.fs.starfarer.api.campaign.comm.MessageParaAPI;
016import com.fs.starfarer.api.campaign.comm.MessageSectionAPI;
017import com.fs.starfarer.api.campaign.econ.MarketAPI;
018import com.fs.starfarer.api.characters.PersonAPI;
019import com.fs.starfarer.api.characters.RelationshipAPI;
020import com.fs.starfarer.api.impl.campaign.ids.Factions;
021import com.fs.starfarer.api.impl.campaign.ids.Tags;
022import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin;
023import com.fs.starfarer.api.impl.campaign.intel.MessageIntel;
024import com.fs.starfarer.api.ui.LabelAPI;
025import com.fs.starfarer.api.ui.TooltipMakerAPI;
026import com.fs.starfarer.api.util.Misc;
027
028public class CoreReputationPlugin implements ReputationActionResponsePlugin {
029        
030        public static class MissionCompletionRep {
031                public float successDelta;
032                public RepLevel successLimit;
033                public float failureDelta;
034                public RepLevel failureLimit;
035                public MissionCompletionRep(float successDelta, RepLevel successLimit,
036                                                                        float failureDelta, RepLevel failureLimit) {
037                        this.successDelta = successDelta;
038                        this.successLimit = successLimit;
039                        this.failureDelta = failureDelta;
040                        this.failureLimit = failureLimit;
041                }
042                
043        }
044        
045        public static class RepActionEnvelope {
046                public RepActions action;
047                public Object param = null;
048                public CommMessageAPI message = null;
049                public TextPanelAPI textPanel = null;
050                public boolean addMessageOnNoChange = true;
051                public boolean withMessage = true;
052                public String reason;
053                public RepActionEnvelope(RepActions action, Object param) {
054                        this.action = action;
055                        this.param = param;
056                }
057                public RepActionEnvelope(RepActions action) {
058                        this.action = action;
059                }
060//              public RepActionEnvelope(RepActions action, Object param, CommMessageAPI message, boolean addMessageOnNoChange) {
061//                      this.action = action;
062//                      this.param = param;
063//                      this.message = message;
064//                      this.addMessageOnNoChange = addMessageOnNoChange;
065//              }
066                public RepActionEnvelope(RepActions action, Object param, CommMessageAPI message, TextPanelAPI textPanel, boolean addMessageOnNoChange) {
067                        this(action, param, message, textPanel, addMessageOnNoChange, true);
068                }
069                public RepActionEnvelope(RepActions action, Object param, TextPanelAPI textPanel, boolean addMessageOnNoChange) {
070                        this(action, param, null, textPanel, addMessageOnNoChange, true);
071                }
072                public RepActionEnvelope(RepActions action, Object param, CommMessageAPI message, TextPanelAPI textPanel, boolean addMessageOnNoChange, boolean withMessage) {
073                        this(action, param, message, textPanel, addMessageOnNoChange, withMessage, null);
074                }
075                public RepActionEnvelope(RepActions action, Object param, TextPanelAPI textPanel, boolean addMessageOnNoChange, boolean withMessage) {
076                        this(action, param, null, textPanel, addMessageOnNoChange, withMessage, null);
077                }
078                public RepActionEnvelope(RepActions action, Object param, TextPanelAPI textPanel, boolean addMessageOnNoChange, boolean withMessage, String reason) {
079                        this(action, param, null, textPanel, addMessageOnNoChange, withMessage, reason);
080                }
081                public RepActionEnvelope(RepActions action, Object param, CommMessageAPI message, TextPanelAPI textPanel, boolean addMessageOnNoChange, boolean withMessage, String reason) {
082                        this.action = action;
083                        this.param = param;
084                        this.message = message;
085                        this.addMessageOnNoChange = addMessageOnNoChange;
086                        this.textPanel = textPanel;
087                        this.withMessage = withMessage;
088                        this.reason = reason;
089                }
090                public RepActionEnvelope(RepActions action, Object param, TextPanelAPI textPanel) {
091                        this.action = action;
092                        this.param = param;
093                        this.textPanel = textPanel;
094                }
095        }
096        
097        public static class CustomRepImpact {
098                public float delta = 0;
099                public RepLevel limit = null;
100                public RepLevel ensureAtBest = null;
101                public RepLevel ensureAtWorst = null;
102                public RepLevel requireAtBest = null;
103                public RepLevel requireAtWorst = null;
104        }
105        
106        public static enum RepActions {
107                COMBAT_NO_DAMAGE_ESCAPE, // now unused
108                
109                COMBAT_NORMAL,
110                COMBAT_AGGRESSIVE,
111                
112                COMBAT_NORMAL_TOFF,
113                COMBAT_AGGRESSIVE_TOFF,
114                
115                COMBAT_HELP_MINOR,
116                COMBAT_HELP_MAJOR,
117                COMBAT_HELP_CRITICAL,
118                
119                COMBAT_FRIENDLY_FIRE,
120                
121                FOOD_SHORTAGE_PLAYER_ENDED_FAST,
122                FOOD_SHORTAGE_PLAYER_ENDED_NORMAL,
123                
124                SYSTEM_BOUNTY_REWARD,
125                PERSON_BOUNTY_REWARD,
126                COMBAT_WITH_ENEMY,
127                
128                TRADE_EFFECT,
129                SMUGGLING_EFFECT,
130                TRADE_WITH_ENEMY,
131                
132                OTHER_FACTION_GOOD_REP_INVESTIGATION_MINOR,
133                OTHER_FACTION_GOOD_REP_INVESTIGATION_MAJOR,
134                OTHER_FACTION_GOOD_REP_INVESTIGATION_CRITICAL,
135                
136                SMUGGLING_INVESTIGATION_GUILTY,
137                COMM_SNIFFER_INVESTIGATION_GUILTY,
138                FOOD_INVESTIGATION_GUILTY,
139                FOOD_INVESTIGATION_GUILTY_MAJOR,
140                
141                CAUGHT_INSTALLING_SNIFFER,
142                
143                CUSTOMS_NOTICED_EVADING,
144                CUSTOMS_CAUGHT_SMUGGLING,
145                CUSTOMS_REFUSED_TOLL,
146                CUSTOMS_REFUSED_FINE,
147                CUSTOMS_COULD_NOT_AFFORD,
148                CUSTOMS_PAID,
149                
150                REP_DECAY_POSITIVE,
151                //REP_DECAY_NEGATIVE,
152                
153                TRANSPONDER_OFF,
154                TRANSPONDER_OFF_REFUSE,
155                
156                CARGO_SCAN_REFUSE,
157                
158                MISSION_SUCCESS,
159                MISSION_FAILURE,
160                
161                MAKE_SUSPICOUS_AT_WORST,
162                
163                MAKE_HOSTILE_AT_BEST,
164                COMMISSION_ACCEPT,
165                COMMISSION_BOUNTY_REWARD,
166                
167                COMMISSION_NEUTRAL_BATTLE_PENALTY,
168                COMMISSION_PENALTY_HOSTILE_TO_NON_ENEMY,
169                
170                SHRINE_OFFERING,
171                
172                INTERDICTED,
173                
174                CUSTOM,
175//              MISSION_COMPLETED_MINOR,
176//              MISSION_COMPLETED_MEDIUM,
177//              MISSION_COMPLETED_IMPORTANT,
178//              
179//              MISSION_FAILED_MINOR,
180//              MISSION_FAILED_MEDIUM,
181//              MISSION_FAILED_IMPORTANT,
182                
183                
184        }
185        
186        public static class RepRewards {
187                public static final float TINY = 0.01f;
188                public static final float SMALL = 0.02f;
189                public static final float MEDIUM = 0.03f;
190                public static final float HIGH = 0.05f;
191                public static final float VERY_HIGH = 0.07f;
192                public static final float EXTREME = 0.1f;
193        }
194        
195        
196
197
198        public ReputationAdjustmentResult handlePlayerReputationAction(Object action, final String factionId) {
199                //final FactionAPI player = Global.getSector().getFaction(Factions.PLAYER);
200                final FactionAPI faction = Global.getSector().getFaction(factionId);
201                if (faction == null) return new ReputationAdjustmentResult(0);
202                return handlePlayerReputationActionInner(action, factionId, null, faction.getRelToPlayer());
203        }
204
205
206        public ReputationAdjustmentResult handlePlayerReputationAction(Object action, PersonAPI person) {
207                return handlePlayerReputationActionInner(action, person.getFaction().getId(), person, person.getRelToPlayer());
208        }
209
210        
211        public ReputationAdjustmentResult handlePlayerReputationActionInner(Object actionObject,
212                                                                                                                                        String factionId,
213                                                                                                                                        PersonAPI person,
214                                                                                                                                        RelationshipAPI delegate) {
215                if (!(actionObject instanceof RepActionEnvelope) && !(actionObject instanceof RepActions)) {
216                        return new ReputationAdjustmentResult(0);
217                }
218                
219                if (Factions.NEUTRAL.equals(factionId)) {
220                        return new ReputationAdjustmentResult(0);
221                }
222                
223//              FactionAPI player = Global.getSector().getFaction(Factions.PLAYER);
224                FactionAPI faction = Global.getSector().getFaction(factionId);
225                
226                CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
227                
228                RepActions action = null;
229                String reason = null;
230                Object param = null;
231                CommMessageAPI message = null;
232                TextPanelAPI panel = null;
233                boolean withMessage = true;
234                boolean addMessageOnNoChange = true;
235                if (actionObject instanceof RepActions) {
236                        action = (RepActions) actionObject;
237                        param = null;
238                } else if (actionObject instanceof RepActionEnvelope) {
239                        RepActionEnvelope envelope = (RepActionEnvelope) actionObject;
240                        action = envelope.action;
241                        param = envelope.param;
242                        message = envelope.message;
243                        panel = envelope.textPanel;
244                        addMessageOnNoChange = envelope.addMessageOnNoChange;
245                        withMessage = envelope.withMessage;
246                        reason = envelope.reason;
247                }
248                
249                float delta = 0;
250                RepLevel limit = null;
251                RepLevel ensureAtBest = null;
252                RepLevel ensureAtWorst = null;
253                RepLevel requireAtBest = null;
254                RepLevel requireAtWorst = null;
255                //RepLevel curr = player.getRelationshipLevel(faction);
256                RepLevel curr = delegate.getLevel();
257                
258                if (action == RepActions.CUSTOM) {
259                        if (!(param instanceof CustomRepImpact)) {
260                                throw new RuntimeException("For RepActions.CUSTOM, use CustomRepImpact as a param in a RepActionEnvelope");
261                        }
262                        
263                        CustomRepImpact impact = (CustomRepImpact) param;
264                        
265                        delta = impact.delta;
266                        limit = impact.limit;
267                        ensureAtBest = impact.ensureAtBest;
268                        ensureAtWorst = impact.ensureAtWorst;
269                        requireAtBest = impact.requireAtBest;
270                        requireAtWorst = impact.requireAtWorst;
271                }
272                
273                switch (action) {
274                case COMBAT_HELP_MINOR:
275                        delta = RepRewards.TINY;
276                        limit = RepLevel.WELCOMING;
277                        requireAtWorst = RepLevel.INHOSPITABLE;
278                        break;
279                case COMBAT_HELP_MAJOR:
280                        delta = RepRewards.MEDIUM;
281                        limit = RepLevel.FRIENDLY;
282                        requireAtWorst = RepLevel.INHOSPITABLE;
283                        break;
284                case COMBAT_HELP_CRITICAL:
285                        delta = RepRewards.HIGH;
286                        limit = RepLevel.COOPERATIVE;
287                        requireAtWorst = RepLevel.INHOSPITABLE;
288                        break;
289//              case COMBAT_NO_DAMAGE_ESCAPE:
290//                      if (delegate.isAtWorst(RepLevel.FAVORABLE)) {
291//                              delta = -RepRewards.HIGH;
292//                      } else {
293//                              delta = -RepRewards.SMALL;
294//                      }
295//                      limit = RepLevel.HOSTILE;
296//                      break;
297                case COMBAT_FRIENDLY_FIRE:
298                        float fpHull = (float) Math.ceil((Float) param);
299                        if (fpHull >= 20f) {
300                                fpHull = 0f;
301                                ensureAtBest = RepLevel.HOSTILE;
302                        }
303                        delta = -1f * fpHull * 0.01f;
304                        break;
305                case COMBAT_NORMAL:
306                        delta = -RepRewards.MEDIUM;
307                        limit = RepLevel.VENGEFUL;
308                        ensureAtBest = RepLevel.HOSTILE;
309                        break;
310                case COMBAT_AGGRESSIVE:
311                        delta = -RepRewards.HIGH;
312                        limit = RepLevel.VENGEFUL;
313                        ensureAtBest = RepLevel.HOSTILE;
314                        break;
315                case COMBAT_NORMAL_TOFF:
316                        delta = -RepRewards.MEDIUM;
317                        limit = RepLevel.VENGEFUL;
318                        break;
319                case COMBAT_AGGRESSIVE_TOFF:
320                        delta = -RepRewards.HIGH;
321                        limit = RepLevel.VENGEFUL;
322                        break;                  
323                case FOOD_SHORTAGE_PLAYER_ENDED_FAST:
324                        delta = getRepRewardForFoodShortage(action, (MarketAPI) param);
325                        limit = RepLevel.FRIENDLY;
326                        requireAtWorst = RepLevel.INHOSPITABLE;
327                        break;
328                case FOOD_SHORTAGE_PLAYER_ENDED_NORMAL:
329                        delta = getRepRewardForFoodShortage(action, (MarketAPI) param);
330                        limit = RepLevel.WELCOMING;
331                        requireAtWorst = RepLevel.INHOSPITABLE;
332                        break;
333                case SYSTEM_BOUNTY_REWARD:
334                        float fp = (Float) param;
335                        if (fp < 10) {
336                                delta = RepRewards.SMALL;
337                                limit = RepLevel.WELCOMING;
338                        } else if (fp < 30) {
339                                delta = RepRewards.MEDIUM;
340                                limit = RepLevel.FRIENDLY;
341                        } else {
342                                delta = RepRewards.HIGH;
343                                limit = RepLevel.COOPERATIVE;
344                        }
345                        requireAtWorst = RepLevel.VENGEFUL;
346                        break;
347                case PERSON_BOUNTY_REWARD:
348                        delta = RepRewards.MEDIUM;
349                        limit = RepLevel.COOPERATIVE;
350                        requireAtWorst = RepLevel.VENGEFUL;
351                        break;
352                case COMBAT_WITH_ENEMY:
353                        fp = (Float) param;
354                        if (fp < 10) {
355                                delta = RepRewards.TINY;
356                                limit = RepLevel.WELCOMING;
357                        } else if (fp < 30) {
358                                delta = RepRewards.SMALL;
359                                limit = RepLevel.FRIENDLY;
360                        } else {
361                                delta = RepRewards.MEDIUM;
362                                limit = RepLevel.COOPERATIVE;
363                        }
364                        requireAtWorst = RepLevel.VENGEFUL;
365                        break;
366                case TRADE_EFFECT:
367                        delta = (Float) param * 0.01f;
368                        limit = RepLevel.WELCOMING;
369                        //if (faction.getId().equals(Factions.PIRATES)) {
370//                      if (faction.getCustom().optBoolean(Factions.CUSTOM_WILL_TRADE_WHEN_HOSTILE)) {
371//                              requireAtWorst = RepLevel.HOSTILE;
372//                      } else {
373                                requireAtWorst = RepLevel.INHOSPITABLE;
374//                      }
375                        break;
376                case SMUGGLING_EFFECT:
377                        delta = -(Float) param * 0.01f;
378                        limit = RepLevel.INHOSPITABLE;
379                        break;
380                case TRADE_WITH_ENEMY:
381                        delta = -(Float) param * 0.01f;
382                        limit = RepLevel.HOSTILE;
383                        break;
384                case SMUGGLING_INVESTIGATION_GUILTY:
385                        delta = -RepRewards.HIGH;
386                        limit = RepLevel.HOSTILE;
387                        ensureAtBest = RepLevel.INHOSPITABLE;
388                        break;
389                case OTHER_FACTION_GOOD_REP_INVESTIGATION_MINOR:
390                        delta = -RepRewards.HIGH;
391                        limit = RepLevel.HOSTILE;
392                        break;
393                case OTHER_FACTION_GOOD_REP_INVESTIGATION_MAJOR:
394                        delta = -RepRewards.HIGH;
395                        limit = RepLevel.HOSTILE;
396                        ensureAtBest = RepLevel.INHOSPITABLE;
397                        break;
398                case OTHER_FACTION_GOOD_REP_INVESTIGATION_CRITICAL:
399                        delta = -RepRewards.HIGH;
400                        limit = RepLevel.HOSTILE;
401                        ensureAtBest = RepLevel.HOSTILE;
402                        break;
403                case CAUGHT_INSTALLING_SNIFFER:
404                        delta = -RepRewards.TINY;
405                        limit = RepLevel.INHOSPITABLE;
406                        break;
407                case COMM_SNIFFER_INVESTIGATION_GUILTY:
408                        delta = -RepRewards.SMALL;
409                        limit = RepLevel.INHOSPITABLE;
410                        break;
411                case FOOD_INVESTIGATION_GUILTY:
412                        delta = -RepRewards.HIGH;
413                        limit = RepLevel.INHOSPITABLE;
414                        break;
415                case FOOD_INVESTIGATION_GUILTY_MAJOR:
416                        delta = -RepRewards.HIGH;
417                        limit = RepLevel.HOSTILE;
418                        ensureAtBest = RepLevel.SUSPICIOUS;
419                        break;
420                case CUSTOMS_NOTICED_EVADING:
421                        delta = -RepRewards.MEDIUM;
422                        limit = RepLevel.HOSTILE;
423                        break;
424                case CUSTOMS_CAUGHT_SMUGGLING:
425                        delta = -(Float) param * 0.01f;
426                        limit = RepLevel.HOSTILE;
427                        break;
428                case CUSTOMS_REFUSED_TOLL:
429                        delta = -RepRewards.MEDIUM;
430                        limit = RepLevel.HOSTILE;
431                        break;
432                case CUSTOMS_REFUSED_FINE:
433                        delta = -RepRewards.VERY_HIGH;
434                        limit = RepLevel.HOSTILE;
435                        break;
436                case CUSTOMS_COULD_NOT_AFFORD:
437                        delta = -RepRewards.SMALL;
438                        limit = RepLevel.INHOSPITABLE;
439                        break;
440                case CUSTOMS_PAID:
441                        delta = RepRewards.TINY;
442                        limit = RepLevel.WELCOMING;
443                        break;
444                case REP_DECAY_POSITIVE:
445                        delta = .15f;
446                        limit = RepLevel.NEUTRAL;
447                        requireAtWorst = RepLevel.INHOSPITABLE;
448                        break;
449                case MISSION_SUCCESS:
450                        MissionCompletionRep rep = (MissionCompletionRep) param;
451                        delta = rep.successDelta;
452                        limit = rep.successLimit;
453                        break;
454                case MISSION_FAILURE:
455                        rep = (MissionCompletionRep) param;
456                        delta = rep.failureDelta;
457                        limit = rep.failureLimit;
458                        break;
459                case TRANSPONDER_OFF:
460                        if (person != null) {
461                                delta = -RepRewards.MEDIUM;
462                        } else {
463                                delta = -RepRewards.SMALL;
464                        }
465                        limit = RepLevel.HOSTILE;
466                        break;
467                case TRANSPONDER_OFF_REFUSE:
468                case CARGO_SCAN_REFUSE:
469                        if (person != null) {
470                                delta = -RepRewards.HIGH;
471                        } else {
472                                delta = -RepRewards.MEDIUM;
473                        }
474                        limit = RepLevel.HOSTILE;
475                        break;
476                case COMMISSION_ACCEPT:
477                        delta = RepRewards.HIGH;
478                        break;
479                case SHRINE_OFFERING:
480                        delta = RepRewards.MEDIUM;
481                        limit = RepLevel.FRIENDLY;
482                        break;
483                case INTERDICTED:
484                        delta = -RepRewards.TINY;
485                        limit = RepLevel.INHOSPITABLE;
486                        break;
487                case MAKE_HOSTILE_AT_BEST:
488                        delta = 0;
489                        ensureAtBest = RepLevel.HOSTILE;
490                        break;
491                case MAKE_SUSPICOUS_AT_WORST:
492                        delta = 0;
493                        ensureAtWorst = RepLevel.SUSPICIOUS;
494                        break;
495                case COMMISSION_BOUNTY_REWARD:
496                        fp = (Float) param;
497                        if (fp < 20) {
498                                delta = RepRewards.TINY;
499                                limit = RepLevel.FRIENDLY;
500                        } else if (fp < 50) {
501                                delta = RepRewards.SMALL;
502                                limit = RepLevel.COOPERATIVE;
503                        } else {
504                                delta = RepRewards.MEDIUM;
505                                limit = RepLevel.COOPERATIVE;
506                        }
507                        break;
508                case COMMISSION_PENALTY_HOSTILE_TO_NON_ENEMY:
509                        //delta = -RepRewards.MEDIUM;
510                        fp = (Float) param;
511                        if (fp < 20) {
512                                delta = -RepRewards.TINY;
513                        } else if (fp < 50) {
514                                delta = -RepRewards.SMALL;
515                        } else {
516                                delta = -RepRewards.MEDIUM;
517                        }
518                        limit = RepLevel.INHOSPITABLE;
519                        break;
520                }
521
522                if (delta < 0 && delta > -0.01f) delta = -0.01f;
523                if (delta > 0 && delta < 0.01f) delta = 0.01f;
524                delta = Math.round(delta * 100f) / 100f;
525                
526                if (delegate.getTarget() == Global.getSector().getPlayerFaction()) {
527                        delta = 0;
528                }
529                if (delegate.getTarget() == Global.getSector().getPlayerPerson()) {
530                        delta = 0;
531                }
532                
533                float deltaSign = Math.signum(delta);
534                //float before = player.getRelationship(faction.getId());
535                float before = delegate.getRel();
536                
537                if (ensureAtBest != null) {
538                        delegate.ensureAtBest(ensureAtBest);
539                }
540                if (ensureAtWorst != null) {
541                        delegate.ensureAtWorst(ensureAtWorst);
542                }
543                
544                if ((requireAtBest == null || curr.isAtBest(requireAtBest)) &&
545                                (requireAtWorst == null || curr.isAtWorst(requireAtWorst))) {
546                        delegate.adjustRelationship(delta, limit);
547                }
548                
549                //float after = player.getRelationship(faction.getId());
550                float after = delegate.getRel();
551                delta = after - before;
552                
553                //if (delta != 0) {
554                if (withMessage) {
555                        if (Math.abs(delta) >= 0.005f) {
556                                addAdjustmentMessage(delta, faction, person, message, panel, null, null, true, 0f, reason);
557                        } else if (deltaSign != 0 && addMessageOnNoChange) {
558                                addNoChangeMessage(deltaSign, faction, person, message, panel, null, null, true, 0f, reason);
559                        }
560                }
561                
562                if (delta != 0) {
563                        if (person == null) {
564                                Global.getSector().reportPlayerReputationChange(faction.getId(), delta);
565                        } else {
566                                Global.getSector().reportPlayerReputationChange(person, delta);
567                        }
568                }
569                
570                return new ReputationAdjustmentResult(delta);
571        }
572        
573        
574        private float getRepRewardForFoodShortage(RepActions action, MarketAPI market) {
575                float mult = (float) market.getSize() / 10f + 0.5f;
576                float delta = 0;
577                switch (action) {
578                case FOOD_SHORTAGE_PLAYER_ENDED_NORMAL:
579                        delta = RepRewards.MEDIUM;
580                        break;
581                case FOOD_SHORTAGE_PLAYER_ENDED_FAST:
582                        delta = RepRewards.HIGH;
583                        break;
584                }
585                return delta * mult;
586        }
587        
588        
589        
590        public static void addDeltaMessage(float delta, FactionAPI faction, PersonAPI person, TextPanelAPI panel,
591                                                                           TooltipMakerAPI info, Color tc, boolean withCurrent, float pad) {
592                if (delta == 0) {
593                        addNoChangeMessage(delta, faction, person, null, panel, info, tc, withCurrent, pad);
594                } else {
595                        addAdjustmentMessage(delta, faction, person, null, panel, info, tc, withCurrent, pad);
596                }
597                
598        }
599        public static void addNoChangeMessage(float deltaSign, FactionAPI faction, PersonAPI person, CommMessageAPI message, TextPanelAPI panel,
600                        TooltipMakerAPI info, Color tc, boolean withCurrent, float pad) {
601                addNoChangeMessage(deltaSign, faction, person, message, panel, info, tc, withCurrent, pad, null);
602        }
603        public static void addNoChangeMessage(float deltaSign, FactionAPI faction, PersonAPI person, CommMessageAPI message, TextPanelAPI panel,
604                                                                                  TooltipMakerAPI info, Color tc, boolean withCurrent, float pad, String reason) {
605                FactionAPI player = Global.getSector().getFaction(Factions.PLAYER);
606//              String standing = player.getRelationshipLevel(faction).getDisplayName();
607//              standing = standing.toLowerCase();
608                RepLevel level = player.getRelationshipLevel(faction.getId());
609                int repInt = RepLevel.getRepInt(player.getRelationship(faction.getId()));
610                
611                Color textColor = Global.getSettings().getColor("standardTextColor");
612                Color factionColor = faction.getBaseUIColor();
613                Color relColor = faction.getRelColor(player.getId());
614                String targetName = faction.getDisplayNameWithArticle();
615                String targetNameHighlight = faction.getDisplayName();
616                if (Factions.INDEPENDENT.equals(faction.getId())) {
617                        targetName = faction.getDisplayNameLongWithArticle();
618                        targetNameHighlight = faction.getDisplayNameLong();
619                }
620                
621                if (person != null) {
622                        targetName = person.getName().getFullName();
623                        relColor = person.getRelToPlayer().getRelColor();
624                        repInt = RepLevel.getRepInt(person.getRelToPlayer().getRel());
625                        level = person.getRelToPlayer().getLevel();
626                }
627                
628                String standing = "" + repInt + "/100" + " (" + level.getDisplayName().toLowerCase() + ")";
629                
630                
631                
632
633                String text = "Your relationship with " + targetName + 
634                                        ", currently at " + standing + ", is already well-established and is not affected by your recent actions";
635                
636                if (panel == null && info == null) {
637//                      Global.getSector().getCampaignUI().addMessage(text, textColor, 
638//                                      standing, 
639//                                      relColor);
640                        
641                        MessageIntel intel = new MessageIntel();
642                        if (person == null) {
643                                intel.addLine("Relationship with " + targetName + " not affected", null, 
644                                                         new String[] {targetNameHighlight}, 
645                                                                                   factionColor); 
646                                intel.addLine(BaseIntelPlugin.BULLET + "Currently at %s", null, new String[]{standing}, relColor);
647                                if (reason != null) intel.addLine(BaseIntelPlugin.BULLET + reason);
648                                intel.setIcon(faction.getCrest());
649                        } else {
650                                intel.addLine("Relationship with " + targetName + " not affected"); 
651                                intel.addLine(BaseIntelPlugin.BULLET + "Currently at %s", null, new String[]{standing}, relColor);
652                                if (reason != null) intel.addLine(BaseIntelPlugin.BULLET + reason);
653                                intel.setIcon(person.getPortraitSprite());
654                        }
655                        //intel.setIcon(Global.getSettings().getSpriteName("intel_categories", "reputation"));
656                        Global.getSector().getCampaignUI().addMessage(intel);
657                }
658                
659                if (panel != null) {
660                        if (panel.getDialog() != null) {
661                                SectorEntityToken target = panel.getDialog().getInteractionTarget();
662                                if (target != null) {
663                                        if (target.getActivePerson() != null) {
664                                                target.getActivePerson().getMemory();
665                                        }
666                                        target.getMemory();
667                                }
668                        }
669                }
670                
671                if (text != null) {
672                        if (message != null) {
673                                text = text.replaceAll(" by your recent actions", " by this.");
674                                appendToSection2(text, message);
675                                appendToSectionHighlights(message.getSection2(), 
676                                                new String [] {standing}, 
677                                                new Color [] {relColor});
678                                
679                                message.addTag(Tags.REPORT_REP);
680                                if (person == null) {
681                                        message.getCustomMap().put(CommMessageAPI.MESSAGE_FACTION_ID_KEY, faction.getId());
682                                } else {
683                                        message.getCustomMap().put(CommMessageAPI.MESSAGE_PERSON_ID_KEY, person.getId());
684                                }
685                                //message.setSmallIcon(faction.getLogo());
686                        } 
687                        
688                        if (panel != null) {
689                                text = text.replaceAll(" by your recent actions", "");
690                                printToTextPanel(panel, text, 
691                                                new String [] {standing}, 
692                                                new Color [] {relColor});
693                        }
694                }
695                
696                if (info != null) {
697                        if (person == null) {
698                                LabelAPI label = info.addPara("Relationship with " + targetName + " not affected", tc, pad);
699                                label.setHighlight(targetNameHighlight); 
700                                label.setHighlightColors(factionColor); 
701                                if (withCurrent) info.addPara("Currently at %s", 0f, tc, relColor, standing);
702                        } else {
703                                LabelAPI label = info.addPara("Relationship with " + targetName + " not affected", tc, pad);
704                                if (withCurrent) info.addPara("Currently at %s", 0f, tc, relColor, standing);
705                        }
706                }
707        }
708        
709        
710        public static void addCurrentStanding(FactionAPI faction, PersonAPI person, TextPanelAPI panel,
711                        TooltipMakerAPI info, Color tc, float pad) {
712                FactionAPI player = Global.getSector().getFaction(Factions.PLAYER);
713                RepLevel level = player.getRelationshipLevel(faction.getId());
714                int repInt = RepLevel.getRepInt(player.getRelationship(faction.getId()));
715
716                Color factionColor = faction.getBaseUIColor();
717                Color relColor = faction.getRelColor(player.getId());
718                String targetName = faction.getDisplayNameWithArticle();
719                String targetNameHighlight = faction.getDisplayName();
720                if (Factions.INDEPENDENT.equals(faction.getId())) {
721                        targetName = faction.getDisplayNameLongWithArticle();
722                        targetNameHighlight = faction.getDisplayNameLong();
723                }
724
725                if (person != null) {
726                        targetName = person.getName().getFullName();
727                        relColor = person.getRelToPlayer().getRelColor();
728                        repInt = RepLevel.getRepInt(person.getRelToPlayer().getRel());
729                        level = person.getRelToPlayer().getLevel();
730                }
731
732                String standing = "" + repInt + "/100" + " (" + level.getDisplayName().toLowerCase() + ")";
733
734                String text = "Current standing with " + targetName + 
735                                          " is " + standing + "";
736
737                if (panel != null) {
738                        printToTextPanel(panel, text, 
739                                        new String [] {targetNameHighlight, standing}, 
740                                        new Color [] {factionColor, relColor});
741                }
742
743                if (info != null) {
744                        String end = "";
745                        if (pad > 0) {
746                                end = ".";
747                        }
748                        if (person == null) {
749                                LabelAPI label = info.addPara("Current standing with " + targetName + 
750                                                " is %s" + end, pad, tc, relColor, standing);
751                                label.setHighlight(targetNameHighlight, standing); 
752                                label.setHighlightColors(factionColor, relColor);
753                        } else {
754                                LabelAPI label = info.addPara("Current standing with " + targetName + 
755                                                " is %s" + end, pad, tc, relColor, standing);
756                                label.setHighlight(targetNameHighlight, standing); 
757                                label.setHighlightColors(factionColor, relColor);
758                        }
759                }
760        }
761        
762        public static void addRequiredStanding(FactionAPI faction, RepLevel req, PersonAPI person, TextPanelAPI panel,
763                        TooltipMakerAPI info, Color tc, float pad, boolean orBetter) {
764                FactionAPI player = Global.getSector().getFaction(Factions.PLAYER);
765                RepLevel level = req;
766
767                float rel = level.getMin() + 0.01f;
768                
769                PersonAPI fake = Global.getFactory().createPerson();
770                fake.getRelToPlayer().setRel(rel);
771
772                int repInt = RepLevel.getRepInt(rel);
773                Color relColor = fake.getRelToPlayer().getRelColor(level);
774                
775                
776                Color factionColor = faction.getBaseUIColor();
777                String targetName = faction.getDisplayNameWithArticle();
778                String targetNameHighlight = faction.getDisplayName();
779                if (Factions.INDEPENDENT.equals(faction.getId())) {
780                        targetName = faction.getDisplayNameLongWithArticle();
781                        targetNameHighlight = faction.getDisplayNameLong();
782                }
783
784                if (person != null) {
785                        targetName = person.getName().getFullName();
786                        relColor = person.getRelToPlayer().getRelColor();
787                }
788                
789
790                String standing = "" + repInt + "/100" + " (" + level.getDisplayName().toLowerCase() + ")";
791
792                String mid = "or better";
793                if (!orBetter) {
794                        mid = "or worse";
795                }
796                String text = "Requires " + standing + " " + mid + " standing with " + targetName;
797                
798                if (panel != null) {
799                        printToTextPanel(panel, text, 
800                                        new String [] {standing, targetNameHighlight}, 
801                                        new Color [] {relColor, factionColor});
802                }
803
804                if (info != null) {
805                        String end = "";
806                        if (pad > 0) {
807                                end = ".";
808                        }
809                        if (person == null) {
810                                LabelAPI label = info.addPara("Requires %s " + mid + " standing with " + targetName + end, 
811                                                                                          pad, tc, relColor, standing);
812                                label.setHighlight(standing, targetNameHighlight); 
813                                label.setHighlightColors(relColor, factionColor);
814                        } else {
815                                LabelAPI label = info.addPara("Requires %s " + mid + " standing with " + targetName + end, 
816                                                                                          pad, tc, relColor, standing);
817                                label.setHighlight(standing, targetNameHighlight); 
818                                label.setHighlightColors(relColor, factionColor);
819                        }
820                }
821        }
822        
823        
824        public static void addAdjustmentMessage(float delta, FactionAPI faction, PersonAPI person, 
825                        TextPanelAPI panel, 
826                        TooltipMakerAPI info, Color tc, boolean withCurrent, float pad) {
827                addAdjustmentMessage(delta, faction, person, null, panel, info, tc, withCurrent, pad, null);
828        }
829        public static void addAdjustmentMessage(float delta, FactionAPI faction, PersonAPI person, 
830                        CommMessageAPI message, TextPanelAPI panel, 
831                        TooltipMakerAPI info, Color tc, boolean withCurrent, float pad) {
832                addAdjustmentMessage(delta, faction, person, message, panel, info, tc, withCurrent, pad, null);
833        }
834        public static void addAdjustmentMessage(float delta, FactionAPI faction, PersonAPI person, 
835                        TextPanelAPI panel, 
836                        TooltipMakerAPI info, Color tc, boolean withCurrent, float pad,
837                        String reason) {
838                addAdjustmentMessage(delta, faction, person, null, panel, info, tc, withCurrent, pad, reason);
839        }
840        public static void addAdjustmentMessage(float delta, FactionAPI faction, PersonAPI person, 
841                                                        CommMessageAPI message, TextPanelAPI panel, 
842                                                        TooltipMakerAPI info, Color tc, boolean withCurrent, float pad,
843                                                        String reason) {
844                FactionAPI player = Global.getSector().getFaction(Factions.PLAYER);
845                
846                //faction may be null here if it's w/ person
847                
848                RepLevel level = null;
849                int deltaInt = (int) Math.round((Math.abs(delta) * 100f));
850                String targetName = null;
851                String targetNameHighlight = null;
852                Color relColor = null;
853                
854                int repInt = 0;
855                if (faction != null) {
856                        level = player.getRelationshipLevel(faction.getId());
857                        repInt = RepLevel.getRepInt(player.getRelationship(faction.getId()));
858                        targetName = faction.getDisplayNameWithArticle();
859                        targetNameHighlight = faction.getDisplayName();
860                        if (Factions.INDEPENDENT.equals(faction.getId())) {
861                                targetName = faction.getDisplayNameLongWithArticle();
862                                targetNameHighlight  = faction.getDisplayNameLong();
863                        }
864                        relColor = faction.getRelColor(player.getId());
865                }
866                
867                if (person != null) {
868                        targetName = person.getName().getFullName();
869                        relColor = person.getRelToPlayer().getRelColor();
870                        repInt = RepLevel.getRepInt(person.getRelToPlayer().getRel());
871                        level = person.getRelToPlayer().getLevel();
872                }
873                
874                String standing = "" + repInt + "/100" + " (" + level.getDisplayName().toLowerCase() + ")";
875                String text = null;
876                
877                
878                Color textColor = Global.getSettings().getColor("standardTextColor");
879                //Color textColor = Global.getSettings().getColor("textGrayColor");
880                Color factionColor = null;
881                if (faction != null) factionColor = faction.getBaseUIColor();
882                
883                Color deltaColor = Global.getSettings().getColor("textFriendColor");
884                String deltaString = "improved by " + deltaInt;
885                if (Math.abs(delta) <= 0.0049f || deltaInt == 0) {
886                        deltaString = "not affected";
887                        deltaColor = tc;
888                } else if (delta < 0) {
889                        deltaColor = Misc.getNegativeHighlightColor();
890                        deltaString = "reduced by " + deltaInt;
891                }
892                
893                text = "Relationship with " +  targetName + " " + deltaString + ", currently at " + standing + "";
894                
895                if (panel == null && info == null) {
896//                      Global.getSector().getCampaignUI().addMessage(text, textColor, 
897//                                      deltaString, standing, 
898//                                      deltaColor, relColor);
899                        
900                        MessageIntel intel = new MessageIntel();
901                        if (person == null) {
902                                intel.addLine("Relationship with " + targetName + " " + deltaString, null, 
903                                                         new String[] {targetNameHighlight, deltaString}, 
904                                                         factionColor, deltaColor); 
905                                intel.addLine(BaseIntelPlugin.BULLET + "Currently at %s", null, new String[]{standing}, relColor);
906                                if (reason != null) intel.addLine(BaseIntelPlugin.BULLET + reason);
907                                if (faction != null) intel.setIcon(faction.getCrest());
908                        } else {
909                                intel.addLine("Relationship with " + targetName + " " + deltaString, null, 
910                                                 new String[] {deltaString}, 
911                                                                           deltaColor); 
912                                intel.addLine(BaseIntelPlugin.BULLET + "Currently at %s", null, new String[]{standing}, relColor);
913                                if (reason != null) intel.addLine(BaseIntelPlugin.BULLET + reason);
914                                intel.setIcon(person.getPortraitSprite());
915                        }
916                        //intel.setIcon(Global.getSettings().getSpriteName("intel_categories", "reputation"));
917                        Global.getSector().getCampaignUI().addMessage(intel);
918                }
919                
920                if (text != null) {
921                        
922                        if (message != null) {
923                                text += ".";
924                                appendToSection2(text, message);
925                                
926                                appendToSectionHighlights(message.getSection2(), 
927                                                new String [] {deltaString, standing}, 
928                                                new Color [] {deltaColor, relColor});
929                                
930                                message.addTag(Tags.REPORT_REP);
931                                if (person == null) {
932                                        message.getCustomMap().put(CommMessageAPI.MESSAGE_FACTION_ID_KEY, faction.getId());
933                                } else {
934                                        message.getCustomMap().put(CommMessageAPI.MESSAGE_PERSON_ID_KEY, person.getId());
935                                }
936                                //message.setSmallIcon(faction.getLogo());
937                        }
938                        
939                        if (panel != null) {
940                                printToTextPanel(panel, text, 
941                                                new String [] {deltaString, standing},
942                                                new Color [] {deltaColor, relColor});
943                        }
944                }
945                
946                if (info != null) {
947                        if (person == null) {
948//                              LabelAPI label = info.addPara("Relationship with " + targetName + " " + deltaString + 
949//                                              ", currently " + standing, tc, pad);
950//                              label.setHighlight(targetNameHighlight, deltaString, standing); 
951//                              label.setHighlightColors(factionColor, deltaColor, relColor);
952//                              if (delta > 0) {
953//                                      deltaString = "+" + deltaInt;
954//                              } else if (delta < 0) {
955//                                      deltaString = "-" + deltaInt;
956//                              } else {
957//                                      deltaString = "" + deltaInt;
958//                              }
959//                              LabelAPI label = info.addPara(faction.getDisplayName() + " reputation " + deltaString, tc, pad);
960//                              label.setHighlight(targetNameHighlight, deltaString); 
961//                              label.setHighlightColors(factionColor, deltaColor);
962                                
963                                LabelAPI label = info.addPara("Relationship with " + targetName + " " + deltaString, tc, pad);
964                                label.setHighlight(targetNameHighlight, deltaString); 
965                                label.setHighlightColors(factionColor, deltaColor);
966                                //info.setBulletedListMode(BaseIntelPlugin.INDENT);
967                                if (withCurrent) info.addPara("Currently at %s", 0f, tc, relColor, standing);
968                                //info.setBulletedListMode(BaseIntelPlugin.BULLET);
969                        } else {
970                                LabelAPI label = info.addPara("Relationship with " + targetName + " " + deltaString, tc, pad);
971                                label.setHighlight(deltaString); 
972                                label.setHighlightColors(deltaColor); 
973                                if (withCurrent) info.addPara("Currently at %s", 0f, tc, relColor, standing);
974                        }
975                }
976        }
977        
978        private static void printToTextPanel(TextPanelAPI panel, String text, String [] highlights, Color [] colors) {
979                Color textColor = Global.getSettings().getColor("textGrayColor");
980                panel.setFontSmallInsignia();
981                panel.addParagraph(text, textColor);
982                panel.highlightInLastPara(highlights);
983                panel.setHighlightColorsInLastPara(colors);
984                panel.setFontInsignia();
985        }
986        
987        private static void appendToSectionHighlights(MessageSectionAPI section, String [] strings, Color [] colors) {
988                String [] currStrings = section.getHighlights();
989                Color [] currColors = section.getHighlightColors();
990                if (currStrings == null) {
991                        section.setHighlights(strings);
992                        section.setHighlightColors(colors);
993                } else {
994                        List<String> stringList = new ArrayList<String>();
995                        for (String s : currStrings) stringList.add(s);
996                        for (String s : strings) stringList.add(s);
997                        
998                        List<Color> colorList = new ArrayList<Color>();
999                        for (Color s : currColors) colorList.add(s);
1000                        for (Color s : colors) colorList.add(s);
1001                        
1002                        section.setHighlights(stringList.toArray(new String [0]));
1003                        section.setHighlightColors(colorList.toArray(new Color [0]));
1004                }
1005        }
1006        
1007        private static void appendToSection2(String text, CommMessageAPI message) {
1008                List<MessageParaAPI> body = message.getSection2().getBody();
1009                if (body.isEmpty()) {
1010                        message.getSection2().addPara(text);
1011                } else {
1012                        MessageParaAPI lastPara = body.get(body.size() - 1);
1013                        String str = lastPara.getBody();
1014                        str = str + "\n\n" + text;
1015                        lastPara.setBody(str);
1016                }
1017        }
1018
1019        
1020        
1021        
1022//      public static int otherRepInt(float f) {
1023//              int repInt = (int) Math.ceil((Math.round(f * 100f)));
1024//              return repInt;
1025//      }
1026//      
1027//      public static void main(String[] args) {
1028//              float [] tests = new float [] {
1029//                              0.1f,
1030//                              0.0951f,
1031//                              0.105f,
1032//                              0.090001f,
1033//                              0.099999999f,
1034//                              -0.1f,
1035//                              -0.0951f,
1036//                              -0.105f,
1037//                              -0.090001f,
1038//                              -0.099999999f,
1039//              };
1040//              
1041//              for (float f : tests) {
1042//                      System.out.println(String.format("In: %s, old: %s, new: %s", "" + f, "" + otherRepInt(f), "" + RepLevel.getRepInt(f)));
1043//              }
1044//              
1045////            for (float f = -1; f <= 1f; f += 0.00001f) {
1046////                    int before = otherRepInt(f);
1047////                    int after = getRepInt(f);
1048////                    if (before != after) {
1049////                            System.out.println("NOT EQUAL FOR: " + f);
1050////                    }
1051////            }
1052//              
1053//              for (float f = -1; f <= 1f; f += 0.00001f) {
1054//                      int i = RepLevel.getRepInt(f);
1055//                      RepLevel level = RepLevel.getLevelFor(f);
1056//                      RepLevel fromInt = RepLevel.getLevelFor(i / 100f);
1057//                      if (level != fromInt) {
1058//                              System.out.println("FAILED FOR: " + f + ", should be " + level + ", is " + fromInt);
1059////                            RepLevel.getRepInt(f);
1060////                            level = RepLevel.getLevelFor(f);
1061////                            fromInt = RepLevel.getLevelFor(i / 100f);
1062//                      }
1063//              }
1064//      }
1065}
1066
1067
1068
1069