Пример #1
0
        public static async Task SendWarAndSaveAsync(MainRepository repo, CountryWar war)
        {
            MapLog mapLog = null;

            await repo.CountryDiplomacies.SetWarAsync(war);

            if ((war.Status == CountryWarStatus.InReady && war.RequestedStopCountryId == 0) || war.Status == CountryWarStatus.Stoped)
            {
                // 戦争を周りに通知
                var country1 = await repo.Country.GetAliveByIdAsync(war.RequestedCountryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                var country2 = await repo.Country.GetAliveByIdAsync(war.InsistedCountryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                mapLog = new MapLog
                {
                    ApiGameDateTime = (await repo.System.GetAsync()).GameDateTime,
                    Date            = DateTime.Now,
                    IsImportant     = true,
                };
                if (war.Status == CountryWarStatus.InReady)
                {
                    if (war.RequestedStopCountryId == 0)
                    {
                        mapLog.EventType = EventType.WarInReady;
                        if (war.Mode == CountryWarMode.Religion)
                        {
                            mapLog.Message = "<country>" + country1.Name + "</country> は、<date>" + war.StartGameDate.ToString() + "</date> より <country>" + country2.Name + "</country> と宗教戦争を開始します";
                        }
                        else
                        {
                            mapLog.Message = "<country>" + country1.Name + "</country> は、<date>" + war.StartGameDate.ToString() + "</date> より <country>" + country2.Name + "</country> へ侵攻します";
                        }
                        await PushNotificationService.SendCountryAsync(repo, "宣戦布告", $"{war.StartGameDate.ToString()} より {country2.Name} と戦争します", country1.Id);

                        await PushNotificationService.SendCountryAsync(repo, "宣戦布告", $"{war.StartGameDate.ToString()} より {country1.Name} と戦争します", country2.Id);
                    }
                }
                else if (war.Status == CountryWarStatus.Stoped)
                {
                    mapLog.EventType = EventType.WarStopped;
                    mapLog.Message   = "<country>" + country1.Name + "</country> と <country>" + country2.Name + "</country> の戦争は停戦しました";
                    await PushNotificationService.SendCountryAsync(repo, "停戦", $"{country2.Name} との戦争は停戦しました", country1.Id);

                    await PushNotificationService.SendCountryAsync(repo, "停戦", $"{country1.Name} との戦争は停戦しました", country2.Id);
                }
                await repo.MapLog.AddAsync(mapLog);
            }

            await repo.SaveChangesAsync();

            await StatusStreaming.Default.SendAllAsync(ApiData.From(war));

            if (mapLog != null)
            {
                await StatusStreaming.Default.SendAllAsync(ApiData.From(mapLog));

                await AnonymousStreaming.Default.SendAllAsync(ApiData.From(mapLog));
            }
        }
Пример #2
0
 /// <summary>
 /// ログを追加
 /// </summary>
 /// <param name="log">追加するログ</param>
 public async Task AddAsync(MapLog log)
 {
     try
     {
         await this.container.Context.MapLogs.AddAsync(log);
     }
     catch (Exception ex)
     {
         this.container.Error(ex);
     }
 }
Пример #3
0
        public static async Task <MapLog> AddMapLogAsync(MainRepository repo, bool isImportant, EventType type, string message)
        {
            var system = await repo.System.GetAsync();

            var log = new MapLog
            {
                ApiGameDateTime = system.GameDateTime,
                Date            = DateTime.Now,
                EventType       = type,
                IsImportant     = isImportant,
                Message         = message,
            };
            await repo.MapLog.AddAsync(log);

            await repo.SaveChangesAsync();

            await StatusStreaming.Default.SendAllAsync(ApiData.From(log));

            await AnonymousStreaming.Default.SendAllAsync(ApiData.From(log));

            return(log);
        }
Пример #4
0
        public async Task SetCountryAllianceAsync(
            [FromRoute] uint targetId,
            [FromBody] CountryAlliance param)
        {
            CountryAlliance            alliance;
            MapLog                     mapLog = null;
            Optional <CountryAlliance> old    = default;

            if (param.Status != CountryAllianceStatus.Available &&
                param.Status != CountryAllianceStatus.ChangeRequesting &&
                param.Status != CountryAllianceStatus.Dismissed &&
                param.Status != CountryAllianceStatus.InBreaking &&
                param.Status != CountryAllianceStatus.Requesting &&
                param.Status != CountryAllianceStatus.Changed &&
                param.Status != CountryAllianceStatus.None)
            {
                ErrorCode.InvalidParameterError.Throw();
            }

            using (var repo = MainRepository.WithReadAndWrite())
            {
                var system = await repo.System.GetAsync();

                var self = await repo.Character.GetByIdAsync(this.AuthData.CharacterId).GetOrErrorAsync(ErrorCode.LoginCharacterNotFoundError);

                var myPosts = await repo.Country.GetCharacterPostsAsync(self.Id);

                if (!myPosts.Any(p => p.Type.CanDiplomacy()))
                {
                    ErrorCode.NotPermissionError.Throw();
                }

                if (system.IsBattleRoyaleMode)
                {
                    // 全国戦争中に同盟操作はできない
                    ErrorCode.InvalidOperationError.Throw();
                }

                var target = await repo.Country.GetAliveByIdAsync(targetId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                if (target.AiType != CountryAiType.Human)
                {
                    // 人間の国以外に同盟を申請することはできない
                    ErrorCode.InvalidOperationError.Throw();
                }

                old = await repo.CountryDiplomacies.GetCountryAllianceAsync(self.CountryId, targetId);

                var changeTo = await repo.CountryDiplomacies.GetCountryAllianceChangingValueAsync(self.CountryId, targetId);

                var war = await repo.CountryDiplomacies.GetCountryWarAsync(self.CountryId, targetId);

                if (old.HasData &&
                    old.Data.Status != CountryAllianceStatus.Broken &&
                    old.Data.Status != CountryAllianceStatus.Dismissed &&
                    old.Data.Status != CountryAllianceStatus.None)
                {
                    var o = old.Data;

                    if ((param.Status == CountryAllianceStatus.Available || param.Status == CountryAllianceStatus.ChangeRequesting || param.Status == CountryAllianceStatus.Changed) &&
                        o.Status == CountryAllianceStatus.Requesting)
                    {
                        if (self.CountryId == o.RequestedCountryId)
                        {
                            // 自分で自分の要求を承認しようとした
                            ErrorCode.NotPermissionError.Throw();
                        }
                    }
                    else if (param.Status == CountryAllianceStatus.InBreaking &&
                             (o.Status != CountryAllianceStatus.Available && o.Status != CountryAllianceStatus.ChangeRequesting))
                    {
                        // 結んでいないのに破棄はエラー
                        ErrorCode.NotPermissionError.Throw();
                    }
                    else if ((param.Status == CountryAllianceStatus.None || param.Status == CountryAllianceStatus.Requesting) &&
                             (o.Status == CountryAllianceStatus.Available || o.Status == CountryAllianceStatus.ChangeRequesting))
                    {
                        // 結んでいるものを一瞬でなかったことにするのはエラー
                        ErrorCode.NotPermissionError.Throw();
                    }
                    else if (param.Status == o.Status && param.Status == CountryAllianceStatus.Available)
                    {
                        // 再承認はできない
                        ErrorCode.MeaninglessOperationError.Throw();
                    }
                    else if (param.Status == CountryAllianceStatus.Changed)
                    {
                        if (!changeTo.HasData || o.Status != CountryAllianceStatus.ChangeRequesting)
                        {
                            // 変更提案していないのに承諾はできない
                            ErrorCode.InvalidOperationError.Throw();
                        }
                        else if (changeTo.Data.RequestedCountryId == self.CountryId)
                        {
                            // 自分の変更要求を自分で承認できない
                            ErrorCode.InvalidOperationError.Throw();
                        }
                    }

                    if (param.Status == CountryAllianceStatus.Available || param.Status == CountryAllianceStatus.InBreaking)
                    {
                        param.BreakingDelay = o.BreakingDelay;
                        param.IsPublic      = o.IsPublic;
                        param.CanMissionary = o.CanMissionary;
                        param.Memo          = o.Memo;
                    }
                    else if (param.Status == CountryAllianceStatus.Changed)
                    {
                        param.BreakingDelay = changeTo.Data.BreakingDelay;
                        param.IsPublic      = changeTo.Data.IsPublic;
                        param.CanMissionary = changeTo.Data.CanMissionary;
                        param.Memo          = changeTo.Data.Memo;
                    }
                }
                else
                {
                    if (param.Status != CountryAllianceStatus.Requesting)
                    {
                        // 同盟を結んでいない場合、同盟の要求以外にできることはない
                        ErrorCode.NotPermissionError.Throw();
                    }

                    war.Some((w) =>
                    {
                        if (w.Status == CountryWarStatus.Available ||
                            w.Status == CountryWarStatus.InReady ||
                            w.Status == CountryWarStatus.StopRequesting)
                        {
                            // 戦争中
                            ErrorCode.NotPermissionError.Throw();
                        }
                    });
                }

                alliance = new CountryAlliance
                {
                    RequestedCountryId = self.CountryId,
                    InsistedCountryId  = targetId,
                    BreakingDelay      = param.BreakingDelay,
                    IsPublic           = param.IsPublic,
                    CanMissionary      = param.CanMissionary,
                    Memo   = param.Memo,
                    Status = param.Status == CountryAllianceStatus.Changed ? CountryAllianceStatus.Available : param.Status,
                };
                if (param.Status != CountryAllianceStatus.ChangeRequesting)
                {
                    await repo.CountryDiplomacies.SetAllianceAsync(alliance);
                }
                else
                {
                    alliance.ChangeTargetId = old.Data.Id;
                    alliance.Status         = CountryAllianceStatus.ChangeRequestingValue;
                    old.Data.Status         = CountryAllianceStatus.ChangeRequesting;
                    await repo.CountryDiplomacies.SetAllianceChangingValueAsync(alliance);
                }

                // 同盟関係を周りに通知
                if (alliance.IsPublic && old.HasData && alliance.Status != CountryAllianceStatus.ChangeRequestingValue)
                {
                    if (old.Data.Status == CountryAllianceStatus.Requesting &&
                        alliance.Status == CountryAllianceStatus.Available)
                    {
                        var country1 = await repo.Country.GetByIdAsync(alliance.RequestedCountryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                        var country2 = await repo.Country.GetByIdAsync(alliance.InsistedCountryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                        mapLog = new MapLog
                        {
                            ApiGameDateTime = (await repo.System.GetAsync()).GameDateTime,
                            Date            = DateTime.Now,
                            EventType       = EventType.AllianceStart,
                            IsImportant     = true,
                            Message         = "<country>" + country1.Name + "</country> と <country>" + country2.Name + "</country> は、同盟を締結しました",
                        };
                        await repo.MapLog.AddAsync(mapLog);
                    }
                }

                await repo.SaveChangesAsync();
            }

            // 同盟関係を周りに通知
            if (alliance.IsPublic && alliance.Status != CountryAllianceStatus.ChangeRequestingValue)
            {
                await StatusStreaming.Default.SendAllAsync(ApiData.From(alliance));

                if (mapLog != null)
                {
                    await StatusStreaming.Default.SendAllAsync(ApiData.From(mapLog));

                    await AnonymousStreaming.Default.SendAllAsync(ApiData.From(mapLog));
                }
            }
            else
            {
                await StatusStreaming.Default.SendCountryAsync(ApiData.From(alliance), alliance.RequestedCountryId);

                await StatusStreaming.Default.SendCountryAsync(ApiData.From(alliance), alliance.InsistedCountryId);
            }

            if (alliance.Status == CountryAllianceStatus.ChangeRequestingValue && old.HasData)
            {
                await StatusStreaming.Default.SendCountryAsync(ApiData.From(old.Data), alliance.RequestedCountryId);

                await StatusStreaming.Default.SendCountryAsync(ApiData.From(old.Data), alliance.InsistedCountryId);
            }
        }
Пример #5
0
        public async Task SetCountryWarAsync(
            [FromRoute] uint targetId,
            [FromBody] CountryWar param)
        {
            CountryWar war;
            Optional <CountryAlliance> alliance;
            MapLog mapLog = null;

            if (param.Status != CountryWarStatus.InReady &&
                param.Status != CountryWarStatus.StopRequesting &&
                param.Status != CountryWarStatus.Stoped)
            {
                ErrorCode.InvalidParameterError.Throw();
            }

            using (var repo = MainRepository.WithReadAndWrite())
            {
                var system = await repo.System.GetAsync();

                if (system.IsSoftStoped)
                {
                    ErrorCode.SystemSoftStopedError.Throw();
                }

                var self = await repo.Character.GetByIdAsync(this.AuthData.CharacterId).GetOrErrorAsync(ErrorCode.LoginCharacterNotFoundError);

                var myPosts = await repo.Country.GetCharacterPostsAsync(self.Id);

                if (!myPosts.Any(p => p.Type.CanDiplomacy()))
                {
                    ErrorCode.NotPermissionError.Throw();
                }

                if (system.IsBattleRoyaleMode)
                {
                    // 全国戦争中に戦争操作はできない
                    ErrorCode.InvalidOperationError.Throw();
                }

                if (system.RuleSet != GameRuleSet.Religion && param.Mode == CountryWarMode.Religion)
                {
                    // 宗教戦争は宗教ルールでないと布告できない
                    ErrorCode.RuleSetError.Throw();
                }

                var towns = await repo.Town.GetAllAsync();

                var myCountry = await repo.Country.GetAliveByIdAsync(self.CountryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                var target = await repo.Country.GetAliveByIdAsync(targetId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                var wars = await repo.CountryDiplomacies.GetAllWarsAsync();

                var old = await repo.CountryDiplomacies.GetCountryWarAsync(self.CountryId, targetId);

                alliance = await repo.CountryDiplomacies.GetCountryAllianceAsync(self.CountryId, targetId);

                old.Some((o) =>
                {
                    if (o.Status == param.Status)
                    {
                        ErrorCode.MeaninglessOperationError.Throw();
                    }

                    if ((o.Status == CountryWarStatus.Available || o.Status == CountryWarStatus.InReady) &&
                        param.Status == CountryWarStatus.InReady)
                    {
                        // 重複して宣戦布告はできない
                        ErrorCode.MeaninglessOperationError.Throw();
                    }
                    else if (o.Status == CountryWarStatus.StopRequesting && param.Status == CountryWarStatus.Stoped &&
                             o.RequestedStopCountryId == self.CountryId)
                    {
                        // 自分の停戦要求を自分で承認できない
                        ErrorCode.NotPermissionError.Throw();
                    }
                    else if (o.Status == CountryWarStatus.Stoped && param.Status == CountryWarStatus.StopRequesting)
                    {
                        // 一度決まった停戦を撤回できない
                        ErrorCode.NotPermissionError.Throw();
                    }

                    if (o.Status == CountryWarStatus.Stoped && param.Status == CountryWarStatus.InReady)
                    {
                        // 停戦後の再布告
                        if (param.StartGameDate.ToInt() < system.IntGameDateTime + 12 * 12 + 1 ||
                            param.StartGameDate.Year < Config.StartYear + Config.UpdateStartYear + Config.CountryBattleStopDuring / 12)
                        {
                            // 開戦が早すぎる
                            ErrorCode.InvalidParameterError.Throw();
                        }
                        else if (param.StartGameDate.ToInt() > system.IntGameDateTime + 12 * 24)
                        {
                            // 開戦が遅すぎる
                            ErrorCode.InvalidParameterError.Throw();
                        }
                    }
                    else if (o.Status == CountryWarStatus.StopRequesting && param.Status == CountryWarStatus.InReady)
                    {
                        // 停戦撤回または拒否
                        if (o.StartGameDate.ToInt() <= system.GameDateTime.ToInt())
                        {
                            // 開戦後の場合は開戦扱い
                            param.Status = CountryWarStatus.Available;
                        }
                    }

                    param.RequestedStopCountryId = o.RequestedStopCountryId;
                    if (param.Status == CountryWarStatus.StopRequesting)
                    {
                        param.RequestedStopCountryId = self.CountryId;
                    }

                    param.RequestedCountryId = o.RequestedCountryId;
                    param.InsistedCountryId  = o.InsistedCountryId;
                    param.StartGameDate      = o.StartGameDate;
                    param.Mode = o.Mode;
                });
                old.None(() =>
                {
                    if (param.Mode == CountryWarMode.Religion)
                    {
                        if (myCountry.Religion == ReligionType.Any || myCountry.Religion == ReligionType.None)
                        {
                            // 国教を持たない国は宗教戦争を布告できない
                            ErrorCode.InvalidOperationError.Throw();
                        }

                        if (target.Religion == myCountry.Religion)
                        {
                            // 同じ宗教の国には宗教戦争を布告できない
                            ErrorCode.ReligionError.Throw();
                        }
                    }

                    if (wars.Where(w => w.Status == CountryWarStatus.Available || w.Status == CountryWarStatus.InReady || w.Status == CountryWarStatus.StopRequesting)
                        .Where(w => w.IsJoin(myCountry.Id) || w.IsJoin(target.Id))
                        .Any(w => w.Mode != param.Mode))
                    {
                        // 就業戦争と通常戦争を両方することはできない
                        ErrorCode.InvalidWarModeError.Throw();
                    }

                    if (!towns.GetAroundCountries(towns.Where(t => t.CountryId == param.InsistedCountryId)).Contains(param.RequestedCountryId))
                    {
                        // 飛び地布告
                        ErrorCode.InvalidOperationError.Throw();
                    }

                    if (param.Status == CountryWarStatus.StopRequesting || param.Status == CountryWarStatus.Stoped)
                    {
                        // 存在しない戦争を停戦にはできない
                        ErrorCode.NotPermissionError.Throw();
                    }
                    else if (param.StartGameDate.ToInt() < system.IntGameDateTime + 12 * 12 + 1 ||
                             param.StartGameDate.Year < Config.StartYear + Config.UpdateStartYear + Config.CountryBattleStopDuring / 12)
                    {
                        // 開戦が早すぎる
                        ErrorCode.InvalidParameterError.Throw();
                    }
                    else if (param.StartGameDate.ToInt() > system.IntGameDateTime + 12 * 24)
                    {
                        // 開戦が遅すぎる
                        ErrorCode.InvalidParameterError.Throw();
                    }
                });

                alliance.Some((a) =>
                {
                    if (a.Status == CountryAllianceStatus.Available ||
                        a.Status == CountryAllianceStatus.ChangeRequesting ||
                        a.Status == CountryAllianceStatus.InBreaking)
                    {
                        // 同盟が有効中
                        ErrorCode.NotPermissionError.Throw();
                    }
                    if (a.Status == CountryAllianceStatus.Requesting)
                    {
                        // 自動で同盟申請を却下する
                        a.Status = CountryAllianceStatus.Broken;
                    }
                });

                war = new CountryWar
                {
                    RequestedCountryId     = param.RequestedCountryId,
                    InsistedCountryId      = param.InsistedCountryId,
                    StartGameDate          = param.StartGameDate,
                    Status                 = param.Status,
                    RequestedStopCountryId = param.RequestedStopCountryId,
                    Mode = param.Mode,
                };

                await CountryService.SendWarAndSaveAsync(repo, war);
            }

            if (alliance.HasData)
            {
                var a = alliance.Data;
                await StatusStreaming.Default.SendCountryAsync(ApiData.From(a), a.RequestedCountryId);

                await StatusStreaming.Default.SendCountryAsync(ApiData.From(a), a.InsistedCountryId);
            }
        }
Пример #6
0
        public async Task SetPromotionStatusAsync(
            [FromBody] ChatMessage message)
        {
            Character          newCharacter      = null;
            CharacterLog       charalog          = null;
            CharacterLog       senderCharalog    = null;
            MapLog             maplog            = null;
            Town               newTown           = null;
            Town               oldTown           = null;
            CountryMessage     commanders        = null;
            IEnumerable <uint> oldTownCharacters = null;
            IEnumerable <uint> newTownCharacters = null;

            using (var repo = MainRepository.WithReadAndWrite())
            {
                var system = await repo.System.GetAsync();

                var chara = await repo.Character.GetByIdAsync(this.AuthData.CharacterId).GetOrErrorAsync(ErrorCode.CharacterNotFoundError);

                var old = await repo.ChatMessage.GetByIdAsync(message.Id).GetOrErrorAsync(ErrorCode.InvalidParameterError);

                var country = await repo.Country.GetAliveByIdAsync(chara.CountryId);

                if (country.HasData)
                {
                    // 無所属以外は実行できない
                    ErrorCode.InvalidOperationError.Throw();
                }
                if (old.Type != ChatMessageType.Promotion)
                {
                    // 登用文ではない
                    ErrorCode.InvalidOperationError.Throw();
                }

                if (message.Type == ChatMessageType.PromotionAccepted)
                {
                    var sender = await repo.Character.GetByIdAsync(old.TypeData).GetOrErrorAsync(ErrorCode.CharacterNotFoundError);

                    var senderCountry = await repo.Country.GetAliveByIdAsync(old.CharacterCountryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                    if (senderCountry.IntEstablished + Config.CountryBattleStopDuring > system.IntGameDateTime)
                    {
                        var characterCount = await repo.Country.CountCharactersAsync(senderCountry.Id, true);

                        if (characterCount >= Config.CountryJoinMaxOnLimited)
                        {
                            // 戦闘解除前の国に士官できない
                            ErrorCode.CantJoinAtSuchCountryhError.Throw();
                        }
                    }

                    var blockActions = await repo.BlockAction.GetAvailableTypesAsync(chara.Id);

                    if (blockActions.Contains(BlockActionType.StopJoin) && !system.IsWaitingReset)
                    {
                        ErrorCode.BlockedActionError.Throw();
                    }

                    oldTown = await repo.Town.GetByIdAsync(chara.TownId).GetOrErrorAsync(ErrorCode.TownNotFoundError);

                    newTown = await repo.Town.GetByIdAsync(senderCountry.CapitalTownId).GetOrErrorAsync(ErrorCode.TownNotFoundError);

                    oldTownCharacters = (await repo.Town.GetCharactersWithIconAsync(oldTown.Id)).Select(c => c.Character.Id);
                    newTownCharacters = (await repo.Town.GetCharactersWithIconAsync(newTown.Id)).Select(c => c.Character.Id);
                    commanders        = (await repo.Country.GetMessageAsync(senderCountry.Id, CountryMessageType.Commanders)).Data;

                    var reinforcements = await repo.Reinforcement.GetByCharacterIdAsync(chara.Id);

                    if (reinforcements.Any(r => r.Status == ReinforcementStatus.Active))
                    {
                        ErrorCode.NotPermissionError.Throw();
                    }

                    await CharacterService.ChangeTownAsync(repo, senderCountry.CapitalTownId, chara);

                    await CharacterService.ChangeCountryAsync(repo, senderCountry.Id, new Character[] { chara, });

                    charalog = new CharacterLog
                    {
                        CharacterId  = chara.Id,
                        DateTime     = DateTime.Now,
                        GameDateTime = system.GameDateTime,
                        Message      = $"<character>{sender.Name}</character> の登用に応じ、 <country>{senderCountry.Name}</country> に仕官しました",
                    };
                    senderCharalog = new CharacterLog
                    {
                        CharacterId  = old.TypeData,
                        DateTime     = DateTime.Now,
                        GameDateTime = system.GameDateTime,
                        Message      = $"<character>{chara.Name}</character> があなたの登用に応じ、 <country>{senderCountry.Name}</country> に仕官しました",
                    };
                    maplog = new MapLog
                    {
                        Date            = DateTime.Now,
                        ApiGameDateTime = system.GameDateTime,
                        IsImportant     = false,
                        EventType       = EventType.PromotionAccepted,
                        Message         = $"<character>{chara.Name}</character> は <country>{senderCountry.Name}</country> に仕官しました",
                    };

                    old.Character    = new CharacterChatData(sender, null);
                    old.ReceiverName = chara.Name;
                    old.Type         = message.Type;
                    newCharacter     = chara;
                }
                else if (message.Type == ChatMessageType.PromotionRefused)
                {
                    var sender = await repo.Character.GetByIdAsync(old.TypeData).GetOrErrorAsync(ErrorCode.CharacterNotFoundError);

                    charalog = new CharacterLog
                    {
                        CharacterId  = chara.Id,
                        DateTime     = DateTime.Now,
                        GameDateTime = system.GameDateTime,
                        Message      = $"<character>{sender.Name}</character> の登用を断りました",
                    };
                    senderCharalog = new CharacterLog
                    {
                        CharacterId  = old.TypeData,
                        DateTime     = DateTime.Now,
                        GameDateTime = system.GameDateTime,
                        Message      = $"<character>{chara.Name}</character> は、あなたの登用を断りました",
                    };

                    old.Character    = new CharacterChatData(sender, null);
                    old.ReceiverName = chara.Name;
                    old.Type         = message.Type;
                }
                else
                {
                    ErrorCode.InvalidParameterError.Throw();
                }

                if (maplog != null)
                {
                    await repo.MapLog.AddAsync(maplog);
                }
                if (charalog != null)
                {
                    await repo.Character.AddCharacterLogAsync(charalog);
                }
                if (senderCharalog != null)
                {
                    await repo.Character.AddCharacterLogAsync(senderCharalog);
                }

                message = old;
                await repo.SaveChangesAsync();
            }

            if (newCharacter != null)
            {
                StatusStreaming.Default.UpdateCache(new Character[] { newCharacter, });
                await StatusStreaming.Default.SendCharacterAsync(ApiData.From(newCharacter), newCharacter.Id);
            }
            if (charalog != null)
            {
                await StatusStreaming.Default.SendCharacterAsync(ApiData.From(charalog), charalog.CharacterId);

                await StatusStreaming.Default.SendCharacterAsync(ApiData.From(message), charalog.CharacterId);
            }
            if (senderCharalog != null)
            {
                await StatusStreaming.Default.SendCharacterAsync(ApiData.From(senderCharalog), senderCharalog.CharacterId);

                await StatusStreaming.Default.SendCharacterAsync(ApiData.From(message), senderCharalog.CharacterId);
            }
            if (maplog != null)
            {
                await StatusStreaming.Default.SendAllAsync(ApiData.From(maplog));

                await AnonymousStreaming.Default.SendAllAsync(ApiData.From(maplog));
            }
        }
Пример #7
0
        public async Task SetAsync(
            [FromBody] Reinforcement param)
        {
            Reinforcement reinforcement;
            MapLog        maplog = null;
            Character     self;

            using (var repo = MainRepository.WithReadAndWrite())
            {
                var chara = await repo.Character.GetByIdAsync(this.AuthData.CharacterId).GetOrErrorAsync(ErrorCode.CharacterNotFoundError);

                var countryData = await repo.Country.GetAliveByIdAsync(chara.CountryId);

                var system = await repo.System.GetAsync();

                self = chara;

                if (system.IsBattleRoyaleMode && param.Status == ReinforcementStatus.Active)
                {
                    // 全面戦争中は援軍にいけない
                    ErrorCode.InvalidOperationError.Throw();
                }

                var oldTownId = chara.TownId;

                if (param.Status == ReinforcementStatus.Requesting || param.Status == ReinforcementStatus.RequestCanceled)
                {
                    // chara: 要求するほう

                    var country = countryData.GetOrError(ErrorCode.CountryNotFoundError);

                    var posts         = (await repo.Country.GetPostsAsync(country.Id)).Where(p => p.CharacterId == chara.Id);
                    var hasPermission = posts.Any(p => p.Type.CanDiplomacy());

                    if (!hasPermission)
                    {
                        ErrorCode.NotPermissionError.Throw();
                    }

                    var targetCharacter = await repo.Character.GetByIdAsync(param.CharacterId).GetOrErrorAsync(ErrorCode.CharacterNotFoundError);

                    var targetCountry = await repo.Country.GetByIdAsync(targetCharacter.CountryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                    var olds = await repo.Reinforcement.GetByCharacterIdAsync(targetCharacter.Id);

                    if (country.Id == targetCountry.Id)
                    {
                        ErrorCode.MeaninglessOperationError.Throw();
                    }
                    var alliance = await repo.CountryDiplomacies.GetCountryAllianceAsync(country.Id, targetCountry.Id).GetOrErrorAsync(ErrorCode.NotPermissionError);

                    if (alliance.Status != CountryAllianceStatus.Available && alliance.Status != CountryAllianceStatus.ChangeRequesting)
                    {
                        ErrorCode.NotPermissionError.Throw();
                    }
                    if (olds.Any(r => r.Status == ReinforcementStatus.Active))
                    {
                        ErrorCode.InvalidOperationError.Throw();
                    }
                    if (olds.Any(r => r.Status == ReinforcementStatus.Requesting && r.RequestedCountryId == chara.CountryId))
                    {
                        if (param.Status == ReinforcementStatus.Requesting)
                        {
                            ErrorCode.MeaninglessOperationError.Throw();
                        }
                    }
                    else
                    {
                        if (param.Status == ReinforcementStatus.RequestCanceled)
                        {
                            ErrorCode.InvalidOperationError.Throw();
                        }
                    }

                    if (param.Status == ReinforcementStatus.Requesting)
                    {
                        reinforcement = new Reinforcement
                        {
                            CharacterId        = targetCharacter.Id,
                            CharacterCountryId = targetCountry.Id,
                            RequestedCountryId = country.Id,
                            Status             = ReinforcementStatus.Requesting,
                        };
                        await repo.Reinforcement.AddAsync(reinforcement);
                    }
                    else
                    {
                        reinforcement        = olds.FirstOrDefault(r => r.RequestedCountryId == chara.CountryId);
                        reinforcement.Status = ReinforcementStatus.RequestCanceled;
                    }
                }
                else if (param.Status == ReinforcementStatus.RequestDismissed ||
                         param.Status == ReinforcementStatus.Active ||
                         param.Status == ReinforcementStatus.Returned ||
                         param.Status == ReinforcementStatus.Submited)
                {
                    // chara: 要求されるほう

                    var olds = await repo.Reinforcement.GetByCharacterIdAsync(chara.Id);

                    var old = olds.FirstOrDefault(r => r.CharacterCountryId == chara.CountryId && r.RequestedCountryId == param.RequestedCountryId);

                    if (old == null && param.Status != ReinforcementStatus.Returned && param.Status != ReinforcementStatus.Submited)
                    {
                        ErrorCode.InvalidOperationError.Throw();
                    }

                    if (param.Status == ReinforcementStatus.RequestDismissed)
                    {
                        if (old.Status != ReinforcementStatus.Requesting)
                        {
                            ErrorCode.InvalidOperationError.Throw();
                        }
                    }
                    if (param.Status == ReinforcementStatus.Active)
                    {
                        var country          = countryData.GetOrError(ErrorCode.CountryNotFoundError);
                        var requestedCountry = await repo.Country.GetByIdAsync(param.RequestedCountryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                        if (old.Status != ReinforcementStatus.Requesting)
                        {
                            ErrorCode.InvalidOperationError.Throw();
                        }
                        if (requestedCountry.HasOverthrown)
                        {
                            ErrorCode.InvalidOperationError.Throw();
                        }

                        var alliance = await repo.CountryDiplomacies.GetCountryAllianceAsync(old.RequestedCountryId, old.CharacterCountryId).GetOrErrorAsync(ErrorCode.NotPermissionError);

                        if (alliance.Status != CountryAllianceStatus.Available && alliance.Status != CountryAllianceStatus.ChangeRequesting)
                        {
                            ErrorCode.NotPermissionError.Throw();
                        }

                        var post      = (await repo.Country.GetPostsAsync(chara.CountryId)).Where(p => p.CharacterId == chara.Id);
                        var isMonarch = post.Any(p => p.Type == CountryPostType.Monarch);

                        if (isMonarch && !Config.Game.IsAllowMonarchReinforcement)
                        {
                            ErrorCode.NotPermissionError.Throw();
                        }

                        await CharacterService.ChangeTownAsync(repo, requestedCountry.CapitalTownId, chara);

                        await CharacterService.ChangeCountryAsync(repo, requestedCountry.Id, new Character[] { chara, });

                        // 君主が援軍に行く場合、君主データを残す
                        if (isMonarch)
                        {
                            var monarchPost = post.First(p => p.Type == CountryPostType.Monarch);
                            var monarch     = new CountryPost
                            {
                                CharacterId = chara.Id,
                                CountryId   = old.CharacterCountryId,
                                Type        = CountryPostType.MonarchDisabled,
                            };
                            repo.Country.RemoveCharacterPost(monarchPost);
                            await repo.Country.AddPostAsync(monarch);

                            await StatusStreaming.Default.SendCountryAsync(ApiData.From(monarch), old.CharacterCountryId);
                        }

                        maplog = new MapLog
                        {
                            ApiGameDateTime = system.GameDateTime,
                            Date            = DateTime.Now,
                            EventType       = EventType.ReinforcementActived,
                            IsImportant     = false,
                            Message         = $"<country>{country.Name}</country> の <character>{chara.Name}</character> は、 <country>{requestedCountry.Name}</country> へ援軍に行きました",
                        };
                    }
                    if (param.Status == ReinforcementStatus.Returned)
                    {
                        old = olds.FirstOrDefault(o => o.Status == ReinforcementStatus.Active);

                        if (old == null)
                        {
                            ErrorCode.InvalidOperationError.Throw();
                        }

                        var originalCountry = await repo.Country.GetByIdAsync(old.CharacterCountryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                        if (originalCountry.HasOverthrown)
                        {
                            ErrorCode.InvalidOperationError.Throw();
                        }

                        await CharacterService.ChangeTownAsync(repo, originalCountry.CapitalTownId, chara);

                        await CharacterService.ChangeCountryAsync(repo, originalCountry.Id, new Character[] { chara, });

                        // 援軍に行ったのが君主の場合、復活する
                        var post = await repo.Country.GetCharacterPostsAsync(chara.Id);

                        if (post.Any(p => p.Type == CountryPostType.MonarchDisabled))
                        {
                            repo.Country.RemoveCharacterPosts(chara.Id);
                            var monarch = new CountryPost
                            {
                                CharacterId = chara.Id,
                                CountryId   = old.CharacterCountryId,
                                Type        = CountryPostType.Monarch,
                            };
                            await repo.Country.AddPostAsync(monarch);

                            await StatusStreaming.Default.SendCountryAsync(ApiData.From(monarch), old.CharacterCountryId);
                        }

                        var countryName = countryData.Data?.Name ?? "無所属";
                        maplog = new MapLog
                        {
                            ApiGameDateTime = system.GameDateTime,
                            Date            = DateTime.Now,
                            EventType       = EventType.ReinforcementReturned,
                            IsImportant     = false,
                            Message         = $"<country>{originalCountry.Name}</country> の援軍 <character>{chara.Name}</character> は、 <country>{countryName}</country> から帰還しました",
                        };
                    }
                    if (param.Status == ReinforcementStatus.Submited)
                    {
                        var country = countryData.GetOrError(ErrorCode.CountryNotFoundError);
                        old = olds.FirstOrDefault(o => o.Status == ReinforcementStatus.Active);

                        if (old == null)
                        {
                            ErrorCode.InvalidOperationError.Throw();
                        }

                        var originalCountry = await repo.Country.GetByIdAsync(old.CharacterCountryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                        if (!originalCountry.HasOverthrown)
                        {
                            ErrorCode.InvalidOperationError.Throw();
                        }

                        maplog = new MapLog
                        {
                            ApiGameDateTime = system.GameDateTime,
                            Date            = DateTime.Now,
                            EventType       = EventType.ReinforcementSubmited,
                            IsImportant     = false,
                            Message         = $"<country>{originalCountry.Name}</country> の援軍 <character>{chara.Name}</character> は、 <country>{country.Name}</country> に帰順しました",
                        };
                    }

                    reinforcement        = old;
                    reinforcement.Status = param.Status;
                }
                else
                {
                    ErrorCode.InvalidParameterError.Throw();
                    reinforcement = null;
                }

                if (maplog != null)
                {
                    await repo.MapLog.AddAsync(maplog);
                }

                await repo.SaveChangesAsync();
            }

            // マップログ、援軍情報を通知
            await StatusStreaming.Default.SendCountryAsync(ApiData.From(reinforcement), new uint[] { reinforcement.CharacterCountryId, reinforcement.RequestedCountryId, });

            if (maplog != null)
            {
                await StatusStreaming.Default.SendAllAsync(ApiData.From(maplog));

                await AnonymousStreaming.Default.SendAllAsync(ApiData.From(maplog));
            }
            await StatusStreaming.Default.SendCharacterAsync(ApiData.From(self), self.Id);
        }
Пример #8
0
 public MapLoggingEventArgs(MapLog log)
 {
     this.Log = log;
 }
Пример #9
0
 internal void RaiseLog(MapLog log)
 {
     // using this inline vs checking for null is more thread safe
     OnLog?.Invoke(this, new MapLoggingEventArgs(log));
 }
Пример #10
0
        public static async Task EntryAsync(MainRepository repo, string ipAddress, Character newChara, CharacterIcon newIcon, string password, Country newCountry, string invitationCode, bool isFreeCountry)
        {
            var town = await repo.Town.GetByIdAsync(newChara.TownId).GetOrErrorAsync(ErrorCode.TownNotFoundError);

            var system = await repo.System.GetAsync();

            CheckEntryStatus(system.GameDateTime, ipAddress, newChara, password, newIcon, town, newCountry, isFreeCountry);

            // 文字数チェックしてからエスケープ
            newChara.Name    = HtmlUtil.Escape(newChara.Name);
            newCountry.Name  = HtmlUtil.Escape(newCountry.Name);
            newChara.Message = HtmlUtil.Escape(newChara.Message);

            // 既存との重複チェック
            if (await repo.Character.IsAlreadyExistsAsync(newChara.Name, newChara.AliasId))
            {
                ErrorCode.DuplicateCharacterNameOrAliasIdError.Throw();
            }
            if ((system.IsDebug && (await repo.System.GetDebugDataAsync()).IsCheckDuplicateEntry || !system.IsDebug) &&
                await repo.EntryHost.ExistsAsync(ipAddress))
            {
                ErrorCode.DuplicateEntryError.Throw();
            }

            // 招待コードチェック
            Optional <InvitationCode> invitationCodeOptional = default;

            if (system.InvitationCodeRequestedAtEntry)
            {
                invitationCodeOptional = await repo.InvitationCode.GetByCodeAsync(invitationCode);

                if (!invitationCodeOptional.HasData || invitationCodeOptional.Data.HasUsed || invitationCodeOptional.Data.Aim != InvitationCodeAim.Entry)
                {
                    ErrorCode.InvitationCodeRequestedError.Throw();
                }
            }

            var    updateCountriesRequested = false;
            MapLog maplog = null;
            var    chara  = new Character
            {
                Name                = newChara.Name,
                AliasId             = newChara.AliasId,
                Strong              = newChara.Strong,
                StrongEx            = 0,
                Intellect           = newChara.Intellect,
                IntellectEx         = 0,
                Leadership          = newChara.Leadership,
                LeadershipEx        = 0,
                Popularity          = newChara.Popularity,
                PopularityEx        = 0,
                Contribution        = 0,
                Class               = 0,
                DeleteTurn          = (short)(Config.DeleteTurns - 10),
                LastUpdated         = DateTime.Now,
                LastUpdatedGameDate = system.GameDateTime,
                Message             = newChara.Message,
                Money               = 10_0000 + Math.Max(system.GameDateTime.ToInt() - (Config.StartYear + Config.UpdateStartYear + 4) * 12 - Config.StartMonth, 0) * 800,
                Rice                = 5_0000 + Math.Max(system.GameDateTime.ToInt() - (Config.StartYear + Config.UpdateStartYear + 4) * 12 - Config.StartMonth, 0) * 400,
                SkillPoint          = Math.Max(0, (int)((system.IntGameDateTime - Config.UpdateStartYear * 12) * 0.8f)),
                SoldierType         = SoldierType.Common,
                SoldierNumber       = 0,
                Proficiency         = 0,
                TownId              = newChara.TownId,
                From                = newChara.From,
                Religion            = ReligionType.Any,
                FormationType       = newChara.FormationType,
                IsBeginner          = newChara.IsBeginner,
            };

            chara.SetPassword(password);

            // 出身
            var skills = new List <CharacterSkillType>();
            var items  = new List <CharacterItemType>();

            if (chara.From == CharacterFrom.Warrior)
            {
                skills.Add(CharacterSkillType.Strong1);
                chara.Strong += 20;
            }
            else if (chara.From == CharacterFrom.Civilian)
            {
                skills.Add(CharacterSkillType.Intellect1);
                chara.Intellect += 20;
            }
            else if (chara.From == CharacterFrom.Merchant)
            {
                skills.Add(CharacterSkillType.Merchant1);
                chara.Money += 200000;
            }
            else if (chara.From == CharacterFrom.Engineer)
            {
                skills.Add(CharacterSkillType.Engineer1);
                chara.Strong += 10;
                chara.Money  += 100000;
            }
            else if (chara.From == CharacterFrom.Terrorist)
            {
                skills.Add(CharacterSkillType.Terrorist1);
                chara.Strong     += 15;
                chara.Leadership += 5;
            }
            else if (chara.From == CharacterFrom.People)
            {
                skills.Add(CharacterSkillType.People1);
                chara.Popularity += 20;
            }
            else if (chara.From == CharacterFrom.Tactician)
            {
                skills.Add(CharacterSkillType.Tactician1);
                chara.Strong     += 5;
                chara.Leadership += 15;
            }
            else if (chara.From == CharacterFrom.Scholar)
            {
                skills.Add(CharacterSkillType.Scholar1);
                chara.Intellect += 20;
            }
            else if (chara.From == CharacterFrom.Staff)
            {
                skills.Add(CharacterSkillType.Staff1);
                chara.Intellect += 20;
            }
            else if (chara.From == CharacterFrom.Buddhism)
            {
                if (system.RuleSet == GameRuleSet.SimpleBattle)
                {
                    ErrorCode.RuleSetError.Throw();
                }
                skills.Add(CharacterSkillType.Buddhism1);
                chara.Intellect += 15;
                chara.Religion   = ReligionType.Buddhism;
            }
            else if (chara.From == CharacterFrom.Confucianism)
            {
                if (system.RuleSet == GameRuleSet.SimpleBattle)
                {
                    ErrorCode.RuleSetError.Throw();
                }
                skills.Add(CharacterSkillType.Confucianism1);
                chara.Intellect += 15;
                chara.Religion   = ReligionType.Confucianism;
            }
            else if (chara.From == CharacterFrom.Taoism)
            {
                if (system.RuleSet == GameRuleSet.SimpleBattle)
                {
                    ErrorCode.RuleSetError.Throw();
                }
                skills.Add(CharacterSkillType.Taoism1);
                chara.Intellect += 15;
                chara.Religion   = ReligionType.Taoism;
            }
            else
            {
                ErrorCode.InvalidParameterError.Throw();
            }

            // 来月の更新がまだ終わってないタイミングで登録したときの、武将更新時刻の調整
            if (chara.LastUpdated - system.CurrentMonthStartDateTime > TimeSpan.FromSeconds(Config.UpdateTime))
            {
                chara.IntLastUpdatedGameDate++;
            }

            if (isFreeCountry)
            {
                // 無所属で開始
                chara.CountryId = 0;
                await repo.Character.AddAsync(chara);

                maplog = new MapLog
                {
                    Date            = DateTime.Now,
                    ApiGameDateTime = system.GameDateTime,
                    EventType       = EventType.CharacterEntryToFree,
                    IsImportant     = false,
                    Message         = $"<character>{chara.Name}</character> が無所属に出現しました",
                };
                await repo.MapLog.AddAsync(maplog);
            }
            else if (town.CountryId > 0)
            {
                // 武将総数チェック
                var country = await repo.Country.GetByIdAsync(town.CountryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                if (country.IntEstablished + Config.CountryBattleStopDuring > system.GameDateTime.ToInt())
                {
                    var countryCharaCount = await repo.Country.CountCharactersAsync(country.Id, true);

                    if (countryCharaCount >= Config.CountryJoinMaxOnLimited)
                    {
                        ErrorCode.CantJoinAtSuchCountryhError.Throw();
                    }
                    else if (countryCharaCount + 1 == Config.CountryJoinMaxOnLimited)
                    {
                        updateCountriesRequested = true;
                    }
                }

                // AI国家チェック
                if (country.AiType != CountryAiType.Human)
                {
                    ErrorCode.CantJoinAtSuchCountryhError.Throw();
                }

                // 金と米を仕官先国の武将の平均にあわせる
                if (system.GameDateTime.Year >= Config.UpdateStartYear + Config.CountryBattleStopDuring / 12)
                {
                    var countryCharacters = (await repo.Country.GetCharactersAsync(town.CountryId)).Where(c => c.AiType == CharacterAiType.Human || c.AiType == CharacterAiType.Administrator);
                    if (countryCharacters.Any())
                    {
                        chara.Money = Math.Min((int)countryCharacters.Average(c => c.Money) + 10_0000, chara.Money);
                        chara.Rice  = Math.Min((int)countryCharacters.Average(c => c.Rice) + 5_0000, chara.Rice);
                    }
                }

                chara.CountryId = town.CountryId;
                await repo.Character.AddAsync(chara);

                maplog = new MapLog
                {
                    Date            = DateTime.Now,
                    ApiGameDateTime = system.GameDateTime,
                    EventType       = EventType.CharacterEntry,
                    IsImportant     = false,
                    Message         = $"<character>{chara.Name}</character> が <country>{country.Name}</country> に仕官しました",
                };
                await repo.MapLog.AddAsync(maplog);
            }
            else
            {
                // 重複チェック
                if ((await repo.Country.GetAllAsync()).Any(c => c.Name == newCountry.Name || c.CountryColorId == newCountry.CountryColorId))
                {
                    ErrorCode.DuplicateCountryNameOrColorError.Throw();
                }

                if (system.RuleSet == GameRuleSet.SimpleBattle)
                {
                    newCountry.Civilization = CountryCivilization.None;
                }

                var country = new Country
                {
                    Name           = newCountry.Name,
                    CountryColorId = newCountry.CountryColorId,
                    CapitalTownId  = newChara.TownId,
                    IntEstablished = Math.Max(system.GameDateTime.ToInt(), new GameDateTime {
                        Year = Config.UpdateStartYear, Month = 1,
                    }.ToInt()),
                    HasOverthrown         = false,
                    IntOverthrownGameDate = 0,
                    LastMoneyIncomes      = 0,
                    LastRiceIncomes       = 0,
                    PolicyPoint           = 10000,
                    Religion     = RandomService.Next(new ReligionType[] { ReligionType.Buddhism, ReligionType.Confucianism, ReligionType.Taoism, }),
                    Civilization = newCountry.Civilization,
                };
                updateCountriesRequested = true;
                await repo.Country.AddAsync(country);

                var countries = await repo.Country.GetAllAsync();

                var point = 500;

                if (system.RuleSet != GameRuleSet.Wandering)
                {
                    // 大都市に変更
                    town.SubType = town.Type;
                    MapService.UpdateTownType(town, TownType.Large);

                    // 首都の宗教
                    if (system.RuleSet != GameRuleSet.SimpleBattle)
                    {
                        if (country.Religion == ReligionType.Buddhism)
                        {
                            town.Buddhism    += point;
                            town.Confucianism = Math.Min(town.Confucianism, 999);
                            town.Taoism       = Math.Min(town.Taoism, 999);
                        }
                        if (country.Religion == ReligionType.Confucianism)
                        {
                            town.Confucianism += point;
                            town.Buddhism      = Math.Min(town.Buddhism, 999);
                            town.Taoism        = Math.Min(town.Taoism, 999);
                        }
                        if (country.Religion == ReligionType.Taoism)
                        {
                            town.Taoism      += point;
                            town.Buddhism     = Math.Min(town.Buddhism, 999);
                            town.Confucianism = Math.Min(town.Confucianism, 999);
                        }
                    }
                }
                else
                {
                    country.CapitalTownId = 0;
                    items.Add(CharacterItemType.CastleBlueprint);
                    items.Add(CharacterItemType.CastleBlueprint);
                    items.Add(CharacterItemType.CastleBlueprint);
                    chara.Money += 50_0000 * 3;
                }

                await repo.SaveChangesAsync();

                chara.CountryId = country.Id;
                if (system.RuleSet != GameRuleSet.Wandering)
                {
                    town.CountryId = country.Id;
                }
                await repo.Character.AddAsync(chara);

                await repo.SaveChangesAsync();

                var countryPost = new CountryPost
                {
                    Type        = CountryPostType.Monarch,
                    CountryId   = country.Id,
                    CharacterId = chara.Id,
                };
                await repo.Country.AddPostAsync(countryPost);

                if (system.RuleSet == GameRuleSet.Wandering)
                {
                    maplog = new MapLog
                    {
                        Date            = DateTime.Now,
                        ApiGameDateTime = system.GameDateTime,
                        EventType       = EventType.StartWandering,
                        IsImportant     = true,
                        Message         = $"<character>{chara.Name}</character> は <country>{country.Name}</country> の頭領となり放浪を開始しました",
                    };
                }
                else
                {
                    maplog = new MapLog
                    {
                        Date            = DateTime.Now,
                        ApiGameDateTime = system.GameDateTime,
                        EventType       = EventType.Publish,
                        IsImportant     = true,
                        Message         = $"<character>{chara.Name}</character> が <town>{town.Name}</town> に <country>{country.Name}</country> を建国しました",
                    };
                }
                await repo.MapLog.AddAsync(maplog);
            }

            await repo.SaveChangesAsync();

            // 陣形
            var formation = new Formation
            {
                CharacterId = chara.Id,
                Type        = chara.FormationType,
                Level       = 1,
            };
            await repo.Character.AddFormationAsync(formation);

            if (invitationCodeOptional.HasData)
            {
                var code = invitationCodeOptional.Data;
                code.HasUsed     = true;
                code.Used        = DateTime.Now;
                code.CharacterId = chara.Id;
            }

            var icon = new CharacterIcon
            {
                Type        = newIcon.Type,
                IsAvailable = true,
                IsMain      = true,
                FileName    = newIcon.FileName,
                CharacterId = chara.Id,
            };
            await repo.Character.AddCharacterIconAsync(icon);

            var host = new EntryHost
            {
                CharacterId = chara.Id,
                IpAddress   = ipAddress,
            };
            await repo.EntryHost.AddAsync(host);

            var skillItems = skills.Select(s => new CharacterSkill
            {
                CharacterId = chara.Id,
                Type        = s,
                Status      = CharacterSkillStatus.Available,
            });

            foreach (var si in skillItems)
            {
                await SkillService.SetCharacterAndSaveAsync(repo, si, chara);
            }
            var itemData = items.Select(i => new CharacterItem
            {
                Type        = i,
                CharacterId = chara.Id,
                Status      = CharacterItemStatus.CharacterHold,
            });

            foreach (var id in itemData)
            {
                await ItemService.GenerateItemAndSaveAsync(repo, id);
            }

            await repo.SaveChangesAsync();

            if (updateCountriesRequested)
            {
                var countries = await repo.Country.GetAllForAnonymousAsync();

                await AnonymousStreaming.Default.SendAllAsync(countries.Select(c => ApiData.From(c)));

                await StatusStreaming.Default.SendAllAsync(countries.Select(c => ApiData.From(c)));
            }

            var townData   = ApiData.From(new TownForAnonymous(town));
            var maplogData = ApiData.From(maplog);
            await AnonymousStreaming.Default.SendAllAsync(maplogData);

            await StatusStreaming.Default.SendAllAsync(maplogData);

            await AnonymousStreaming.Default.SendAllAsync(townData);

            await StatusStreaming.Default.SendAllAsync(townData);

            await StatusStreaming.Default.SendCountryAsync(ApiData.From(town), town.CountryId);

            await CharacterService.StreamCharacterAsync(repo, chara);
        }