* @param random A pseudo-random number source.
     * @param cs A <code>ChangeSet</code> to update.
     */
    public void csAddFoundingFather(FoundingFather father, Random random,
                                    ChangeSet cs) {
        Game game = getGame();
        Specification spec = game.getSpecification();
        Europe europe = getEurope();
        boolean europeDirty = false;

        // TODO: We do not want to have to update the whole player
        // just to get the FF into the client.  Use this hack until
        // the client gets proper containers.
        cs.addFather(this, father);

        cs.addMessage(See.only(this),
            new ModelMessage(ModelMessage.MessageType.SONS_OF_LIBERTY,
                             "model.player.foundingFatherJoinedCongress",
                             this)
                      .add("%foundingFather%", father.getNameKey())
                      .add("%description%", father.getDescriptionKey()));
        cs.addHistory(this,
            new HistoryEvent(getGame().getTurn(),
                             HistoryEvent.EventType.FOUNDING_FATHER)
                      .add("%father%", father.getNameKey()));

        List<AbstractUnit> units = father.getUnits();
        if (units != null && !units.isEmpty() && europe != null) {
            createUnits(father.getUnits(), europe);
            europeDirty = true;
        }

        java.util.Map<UnitType, UnitType> upgrades = father.getUpgrades();
        if (upgrades != null) {
            for (Unit u : getUnits()) {
                UnitType newType = upgrades.get(u.getType());
                if (newType != null) {
                    u.setType(newType);
                    cs.add(See.perhaps(), u);
                }
            }
        }

        if (recalculateBellsBonus()) {
            cs.add(See.only(this), this);
        }

        for (Event event : father.getEvents()) {
            String eventId = event.getId();
            if (eventId.equals("model.event.resetNativeAlarm")) {
                for (Player p : game.getPlayers()) {
                    if (!p.isDead() && p.isIndian() && p.hasContacted(this)) {
                        p.setTension(this, new Tension(Tension.TENSION_MIN));
                        for (IndianSettlement is : p.getIndianSettlements()) {
                            if (is.hasContactedSettlement(this)) {
                                is.setAlarm(this,
                                            new Tension(Tension.TENSION_MIN));
                                cs.add(See.only(this), is);
                            }
                        }
                        csChangeStance(Stance.PEACE, p, true, cs);
                    }
                }

            } else if (eventId.equals("model.event.boycottsLifted")) {
                Market market = getMarket();
                for (GoodsType goodsType : spec.getGoodsTypeList()) {
                    if (market.getArrears(goodsType) > 0) {
                        market.setArrears(goodsType, 0);
                        cs.add(See.only(this), market.getMarketData(goodsType));
                    }
                }

            } else if (eventId.equals("model.event.freeBuilding")) {
                BuildingType type = spec.getBuildingType(event.getValue());
                for (Colony colony : getColonies()) {
                    if (colony.canBuild(type)) {
                        colony.addBuilding(new ServerBuilding(game, colony, type));
                        colony.getBuildQueue().remove(type);
                        cs.add(See.only(this), colony);
                        if (isAI()) {
                            colony.firePropertyChange(Colony.REARRANGE_WORKERS, true, false);
                        }
                    }
                }

            } else if (eventId.equals("model.event.seeAllColonies")) {
                for (Tile t : game.getMap().getAllTiles()) {
                    Colony colony = t.getColony();
                    if (colony != null
                        && (ServerPlayer) colony.getOwner() != this) {
                        if (!t.isExploredBy(this)) {
                            t.setExploredBy(this, true);
                        }
                        t.updatePlayerExploredTile(this, false);
                        cs.add(See.only(this), t);
                        for (Tile x : colony.getOwnedTiles()) {
                            if (!x.isExploredBy(this)) {
                                x.setExploredBy(this, true);
                            }
                            x.updatePlayerExploredTile(this, false);
                            cs.add(See.only(this), x);
                        }
                    }
                }

            } else if (eventId.equals("model.event.increaseSonsOfLiberty")) {
                int value = Integer.parseInt(event.getValue());
                GoodsType bells = spec.getLibertyGoodsTypeList().get(0);
                int totalBells = 0;
                for (Colony colony : getColonies()) {
                    float oldRatio = (float) colony.getLiberty()
                        / (colony.getUnitCount() * Colony.LIBERTY_PER_REBEL);
                    float reqRatio = Math.min(1.0f, oldRatio + 0.01f * value);
                    int reqBells = (int) Math.round(Colony.LIBERTY_PER_REBEL
                                                    * colony.getUnitCount()
                                                    * (reqRatio - oldRatio));
                    if (reqBells > 0) { // Can go negative if already over 100%
                        colony.addGoods(bells, reqBells);
                        colony.updateSoL();
                        cs.add(See.only(this), colony);
                        totalBells += reqBells;
                    }
                }
                // Bonus bells from the FF do not count towards recruiting
                // the next one!
                incrementLiberty(-totalBells);

            } else if (eventId.equals("model.event.newRecruits")
                       && europe != null) {
                List<RandomChoice<UnitType>> recruits
                    = generateRecruitablesList();
                for (int i = 0; i < Europe.RECRUIT_COUNT; i++) {
                    if (!hasAbility("model.ability.canRecruitUnit",
                                    europe.getRecruitable(i))) {
                        UnitType newType = RandomChoice
                            .getWeightedRandom(logger,
                                "Replace recruit", random, recruits);
                        europe.setRecruitable(i, newType);
                        europeDirty = true;
                    }
                }

            } else if (eventId.equals("model.event.movementChange")) {
                for (Unit u : getUnits()) {
                    if (u.getMovesLeft() > 0) {
                        u.setMovesLeft(u.getInitialMovesLeft());
                        cs.addPartial(See.only(this), u, "movesLeft");
                    }
                }
            }
        }

        if (europeDirty) cs.add(See.only(this), europe);
    }