Compare commits

..
169 Commits
Author SHA1 Message Date
Hide_D 7a3642296a feat: 전투 시뮬레이터에 히든 버프 반영 가능 2023-02-24 00:25:29 +09:00
Hide_D 87e57aea0e feat: 전투 시뮬레이터에 시드 값 입력 가능
- 시드 값 입력시 반복 횟수는 1회로 고정
- 스킬 성공 여부는 동일하나, 실제 수치가 조금 다른 경우가 관측 이유는 추후 확인
- 히든 버프는 아직 미 반영
2023-02-23 23:48:09 +09:00
Hide_D ea256790ec game: 계략에서 도시 인구별 방어 계산식을 제곱근에서 로그로 변경
- (log(장수수 + 1, 2) - 1.25) * 0.04
- 8명까지는 기존 계산식과 큰 차이 없음
2023-02-23 22:59:10 +09:00
Hide_D 4cbd824ee0 fix: 초기 갱신 없이 국가 삭제시 버그 수정 2023-02-23 00:30:42 +09:00
Hide_D 4db1a4b32e fix: 접속자, 접속량 계산에 문제가 있던 부분 수정 2023-02-23 00:25:44 +09:00
Hide_D c060e05553 refac: 메시지 전달 j_ 코드를 API로 변경
- 메시지 전송
- 최근 메시지 수신
- 이전 메시지 수신
- 메시지 응답
- 연락처 수신
- 메시지 삭제
2023-02-22 01:29:00 +09:00
Hide_D 92cd195276 fix: 사령부 타 수뇌 텍스트 복사의 턴 순서도 수정 2023-02-21 02:32:18 +09:00
Hide_D f9b270fef3 fix: 텍스트 복사에서 턴 번호가 제대로 옮겨지지 않는 버그 수정 2023-02-21 02:29:23 +09:00
Hide_D 3f12dfd8ba feat: 턴 조작기에 '텍스트 복사' 추가 2023-02-21 02:26:52 +09:00
Hide_D d7e57f30eb fix: 사령부 복사하기 순서 지연 수정 시도 2023-02-21 02:04:03 +09:00
Hide_D ff822561cd game: 기병의 수비시 전투력 향상
- 기존 대비 전투력 5% 향상
2023-02-21 01:59:59 +09:00
Hide_D 273973f4b6 fix: Uri 기본 사용 방법 변경 2023-02-20 02:23:54 +09:00
Hide_D c648e2df85 fix: WebUtil Namespace 2023-02-20 01:27:52 +09:00
Hide_D 9b7e0ef169 fix, dep: 사용불가능한 phpuri를 league/uri로 대체
- 테스트 아직 없음
2023-02-20 01:02:18 +09:00
Hide_D 6eccd248ea dep: composer 2.5.4 2023-02-20 00:28:04 +09:00
Hide_D eaaa1c5da8 game: 초토화가 치안, 수비, 성벽도 낮추도록 변경 2023-02-05 15:59:33 +09:00
Hide_D 95776cda5c fix: 궁병이 아닌 경우에도 '맞 선제'가 정상 작동하도록 수정
- 궁병선제사격을 선제사격시도, 선제사격발동으로 분리
- 맞선제의 기준을 궁병이 아니라 '선제'의 활성화 여부로 구분
2023-01-28 03:09:44 +09:00
Hide_D 8ae0323dcc fix: 선제 사격에 저격을 쓰지 못하게 해야함 2023-01-28 02:56:35 +09:00
Hide_D f2d0020d92 fix: 피장파장은 피장파장을 대상으로 할 수 없음 2023-01-27 00:51:12 +09:00
Hide_D 67f3004eb0 fix: 이미 다른 부위에 입찰중인 경우 경매가 열리다 마는 버그 수정 2023-01-27 00:43:11 +09:00
Hide_D f933c0616b fix: 턴시간 고정이 0분만 가능한 버그 수정 2023-01-26 14:36:59 +09:00
Hide_D a240c6f901 game: 아시아 명장전(빙의전용) 생성 2023-01-02 20:05:07 +09:00
Hide_D e2c2ae0360 feat, refact: 메시지 응답 2022-12-05 01:55:38 +09:00
Hide_D bcd0117cdd misc: 메시지 삭제 API 정리 2022-12-05 01:42:54 +09:00
Hide_D 83f233cc99 feat, refac: 메시지 삭제 2022-12-05 01:40:12 +09:00
Hide_D 4f21eab7b1 feat, refact: 메시지 연락 리스트 수신 2022-12-05 01:10:41 +09:00
Hide_D 864ddf7efe feat, refac: 메시지 전송 2022-12-05 00:46:16 +09:00
Hide_D 9d3636cc49 misc: APIHelper에서 array가 반환된 경우 result: true 자동 삽입 2022-12-05 00:42:09 +09:00
Hide_D ce4f656030 fix: 정상 깃수 기준을 1 이상으로 변경 2022-12-02 00:43:43 +09:00
Hide_D a94f080cde fix: 미접속 유산 포인트 부여에서 '이벤트 깃수'를 카운트하는 버그 수정 2022-12-02 00:41:44 +09:00
Hide_D 71ca873c7a fix: msgOption은 null을 허용해야함. 2022-12-02 00:23:07 +09:00
Hide_D 6e0d13e1fb fix: 장수 생성시 보너스 스탯 표기 오류 2022-12-01 22:24:09 +09:00
Hide_D 059c4d999a game: 맞 선제시 이전 패치에서 변경된 전투력 반영 2022-12-01 01:13:43 +09:00
Hide_D f52e357e8a fix: 디버그용 코드 수정 2022-12-01 01:02:13 +09:00
Hide_D 761496be5c game: 정란, 벽력에 선제사격 추가, 벽력 공격력 약화
- 6페이즈 전투 기준으론 공격력 유지
- 벽력기준 돌격, 수비전 등에서 상대적 약화
2022-12-01 01:00:30 +09:00
Hide_D 551972d876 feat, refac: 오래된 메시지 불러오기 2022-11-30 01:32:17 +09:00
Hide_D 81c2fc4d43 game: 궁병의 선제 사격을 일반 공격력의 50%에서 2/3로 변경 2022-11-30 00:14:24 +09:00
Hide_D 3e542fcbfa game: 궁기병의 보병 상성 상향 수준 억제
- 공격력: 12.5% 향상
- 방어력: 9.1% 향상
2022-11-30 00:10:44 +09:00
Hide_D c9ab2c593d game: 궁기병의 보병 상대 전투력 향상
- 공격력 25% 향상 (20% 열세)
- 방어력 20% 향상 (25% 열세)
2022-11-30 00:07:46 +09:00
Hide_D 0c9e00e90a game: 목우의 수비 상성 약화
- 1.2(초기) -> 0.8(무상성) -> 1(현재)
- 25% 아군 피해 증가
2022-11-30 00:04:24 +09:00
Hide_D ea17972478 fix: 제거한 troop.ts 파일 빌드 수정 2022-11-29 02:13:43 +09:00
Hide_D 3d40df9755 feat, refac: 최근 메시지 API 2022-11-29 02:06:57 +09:00
Hide_D b4ac348645 Refac: 메시지 타입 지정으로 MessageType Enum 사용 2022-11-29 01:53:55 +09:00
Hide_D 374611f66c refac: MessageType enum 2022-11-29 01:49:19 +09:00
Hide_D 39b66fd626 misc: 사용되지 않는 구버전 부대편성 코드 제거 2022-11-28 23:51:21 +09:00
Hide_D 75dca322b4 fix: UserID가 null인 경우 대응 2022-11-10 17:14:21 +09:00
Hide_D cfdae1ddfa misc: 관리를 위해 mkdir에 group permission 부여 2022-11-05 15:17:57 +09:00
Hide_D 054a6c7073 feat: 모든 API를 기록하는 시스템
- sqlite3에 기록
- 느려지지 않기를...
2022-11-05 15:00:13 +09:00
Hide_D e93d9e6cf5 feat: API에서 민감한 argument 지정 2022-11-05 14:59:52 +09:00
Hide_D 30d99c6fc3 fix: DummySession에서 get이 잘못됨. 2022-11-05 14:58:22 +09:00
Hide_D 56c9b44c93 game: 이벤트 유니크 분실 메시지를 흥미롭게 변경 2022-11-02 21:17:04 +09:00
Hide_D 919ae5a863 game: 무작위 세계 이벤트 시나리오 가오픈 재생성 주기 단축 2022-11-01 23:00:59 +09:00
Hide_D 43b8e546f6 feat: 시나리오 별 사전 생성 시 재 생성 주기 결정 가능 2022-11-01 23:00:25 +09:00
Hide_D b90aef662b game: 무작위 세계 시나리오 초기 등록 2022-10-30 22:13:39 +09:00
Hide_D 1da47863ae feat: 전역 아이템 망실 이벤트 추가 2022-10-30 22:13:25 +09:00
Hide_D 81bd5c1914 feat: 무작위건국, 무작위수도이전 커맨드 추가 2022-10-30 21:47:24 +09:00
Hide_D b14f9a638f fix: 무작위장수명 모드에서 장수명이 제대로 지정되지 않음 2022-10-30 21:41:12 +09:00
Hide_D 8ff3a5a7a8 feat: GameConst에서 유니크 획득 확률 조정 가능 2022-10-30 21:29:48 +09:00
Hide_D 48c77bd6a2 feat: 장수명 무작위 생성 모드 가능 2022-10-30 15:16:40 +09:00
35a017c1dc fix: 천통 후 서버시드 출력 시 괄호를 열지 않고 닫았던 문제 수정 (#227)
Co-authored-by: Jinhyun Kim <lewha0@gmail.com>
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/227
Reviewed-by: Hide_D <hided62@gmail.com>
Co-authored-by: lewha0 <lewha0@noreply.storage.hided.net>
Co-committed-by: lewha0 <lewha0@noreply.storage.hided.net>
2022-10-10 03:29:48 +09:00
Hide_D a3e8a10da9 game: 건국 시점 유산 포인트 베팅 제공량 상향 2022-10-10 01:39:42 +09:00
Hide_D 142b96836e refac: 신규/복귀 유저 유산 포인트 지급 로직을 조금더 최적화 2022-10-05 00:26:04 +09:00
Hide_D 9be0d2ec2d refac: storeOldGeneral을 General::kill로 이동 2022-10-04 20:38:18 +09:00
Hide_D fd817650e7 fix: 지급 버그 수정 2022-10-04 11:32:52 +09:00
Hide_D 3c6cb96a9b feat: 신규/복귀 유저에게 장수 생성 시 유산 포인트 제공
- 이벤트 깃수 제외 500포인트
- 8기까지 적립
2022-10-04 11:25:40 +09:00
Hide_D c4537454f9 fix: 최대 임관년도 수 계산 버그 재 수정 2022-10-04 10:02:39 +09:00
Hide_D 82cdaa433e fix: 최대 임관년도 수 계산 버그 2022-10-04 01:07:11 +09:00
Hide_D 32dd3ff43f misc: AI에서 삭턴NPC 구분 기준을 1턴 추가 2022-10-04 00:13:52 +09:00
Hide_D 6a5840faaa fix: AI 후방 발령 누락분 수정 2022-10-03 23:38:53 +09:00
Hide_D 5b0a3b064d fix: AI 후방 발령 로직 버그 수정
- 징병시 인구 소모가 없는 경우 후방 발령 제외
- NPC 수뇌일때와 유저 수뇌일 때 도시 인구 계산식 다른 버그 수정
2022-10-03 23:37:07 +09:00
Hide_D 14b8bb9790 fix: 2번 연속 멸망 시 유산 포인트 계산 오류 2022-10-03 11:32:22 +09:00
Hide_D 650f4a5903 fix: 구조상 베팅 당첨 포인트는 은퇴시 반영되어야 함 2022-10-03 00:37:18 +09:00
Hide_D c50410a6da game: 은퇴시 토너먼트 보정치를 100%로
- 실수였음!
2022-10-02 23:27:41 +09:00
Hide_D b2a676cd8b game: 옥란백용구 향상 최대 30% -> 50% 2022-10-02 23:25:00 +09:00
Hide_D 50a75e4543 refac, game: 은퇴 시 포인트 반영 방식 변경
- 반영하지 않고 은퇴 이후로 넘기는 포인트 추가
- 은퇴시 계수를 Obj로 이동
2022-10-02 19:41:38 +09:00
Hide_D 22172ac66f fix: null coalesing 수정 2022-10-02 19:39:35 +09:00
Hide_D 392aaa343d fix: calcGenType을 updateInstance()로 이동 2022-10-02 19:36:17 +09:00
Hide_D d924f47d58 fix: warning 발생 제거 2022-10-02 19:35:05 +09:00
Hide_D 3b70cbe724 fix: GeneralAI env 설정 관련 버그 수정 2022-10-02 17:46:20 +09:00
Hide_D 5c3233f883 misc: 서버 리셋 페이지에서 기본 설정값 변경
- 자율 행동 전부 선택
- 자율 행동 기본 시간 24시간
- 사실모드: 가상
2022-10-02 17:43:40 +09:00
Hide_D b570bfa9d4 fix: NPC선전포고, 긴급포상에서 내부 NPC 국가 상태를 업데이트하도록 수정 2022-10-02 17:37:40 +09:00
Hide_D 270cb25285 refac: GeneralAI에서 상태를 추가 업데이트할 수 있도록 구조 변경 2022-10-02 17:33:23 +09:00
Hide_D 7d3b0db924 game: 계략 성공률을 5%p 하향
- 계략 성공률에 인구수를 반영하기 이전과 비교하여 1명있을 때에는 동일
- 한명도 없을때는 5%p 상승
- 두명 이상일 때에는 이전 대비 성공률 하향
2022-10-02 15:59:30 +09:00
Hide_D 74d310e113 fix: 불가침에서 '까지'는 해당 월을 포함하여야 함 2022-10-02 15:55:31 +09:00
Hide_D 45afb1c090 fix: 수동 은퇴 시 명예의전당에 등록되지 않는 버그 2022-09-27 10:00:44 +09:00
Hide_D 40fc2f8bbf fix: NPC 순간이동이 보급이 끊긴 도시에도 갈 수 있는 버그 수정 2022-09-24 22:29:58 +09:00
Hide_D a9de5a92e1 build: pre-commit에 lint 제거 2022-09-24 20:58:56 +09:00
Hide_D c592b00c3f game: 피장파장에 추가되었던 글로벌 전략 1턴 제거 2022-09-24 20:57:44 +09:00
Hide_D 2c81be4d12 game: 계략 방어 확률에 도시 거주 장수 수 반영
- sqrt(장수 수) * 5%p
2022-09-23 21:59:51 +09:00
Hide_D f10289f7b6 game: 피장파장은 이제 전략
- 글로벌 쿨 1턴
- 피장파장 쿨 8턴
2022-09-23 21:56:15 +09:00
Hide_D c1f06b4ce5 fix: 최대 임관 년도 수 제어 규약 우회 2022-09-22 11:54:47 +09:00
Hide_D 9ad3dbba90 game: 배신 관련 최종 수정, 20%부터, +10%p씩
- 공지 추가
2022-09-21 23:25:20 +09:00
Hide_D 12c62f87f7 game: 초기 배신 수치 추가 보정
- 배신 수치를 '2'로 변경.
- 명성 패널티를 30%로 시작해서 45%, 60%
2022-09-21 23:16:29 +09:00
Hide_D 635f1ae077 feat, game: 초반 '배신 수치' 1 증가, 배신 패널티 증가
- 184년 1월부터 배신수치 1 증가.
- 배신 패널티 당 15%, 최대 6회
2022-09-21 23:12:56 +09:00
Hide_D c89bd2f63f fix: 하야, 망명 시 최대 임관 년수가 반영되지 않는 버그 수정 2022-09-21 22:48:55 +09:00
Hide_D 2f94a8a2ca fix: 가오픈 기간 중 사망 메시지에서 조사가 중복되어 나오던 문제 수정 (#226)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/226
Reviewed-by: Hide_D <hided62@gmail.com>
2022-09-14 12:07:08 +09:00
Jinhyun Kim 85b0d35af0 fix: 가오픈 기간 중 사망 메시지에서 조사가 중복되어 나오던 문제 수정 2022-09-14 11:42:19 +09:00
Hide_D b25acacb1e fix: 징병 특기에 '비용 감소' 제거 누락 2022-09-10 19:04:46 +09:00
Hide_D c05a43f3b1 fix(oauth): 이메일 변경 시 oauthID를 받아오지 못하는 분기 수정 2022-09-09 03:28:18 +09:00
Hide_D d99976daa9 fix(oauth): 카카오로그인에서 이메일만 바뀐 경우 이메일 갱신 2022-09-09 03:11:34 +09:00
Hide_D 62f53d09bf feat, game: 징병 전특 리밸런싱, 징병/소집해제시 인구 변동 트리거 설정 2022-09-06 19:48:52 +09:00
Hide_D 88c78ec892 game, misc: 작위 상승 메시지 변경 2022-09-01 02:49:20 +09:00
Hide_D 006ca76922 refac: ExecuteEngine 반환 타입 변경 2022-08-30 22:51:14 +09:00
Hide_D 8cb2e2a447 fix: OAuth Redirect UTI가 사전 값과 다른 경우 domain 보정 2022-08-28 18:00:53 +09:00
Hide_D 517c85d003 misc: oauth.php 에러 상세 표기 2022-08-28 17:37:55 +09:00
Hide_D 83556b710c fix, feat: HTTP_HOST가 다른 경우에도 oauth redirect 허용
- oauth 대상에서 redirect 허용 host를 설정해야함.
2022-08-28 17:24:25 +09:00
Hide_D a43b9091f8 feat: WebUtil::replaceDomain 2022-08-28 17:21:37 +09:00
Hide_D e83a1bef49 fix, misc: 사이시옷 수정 2022-08-28 15:45:44 +09:00
Hide_D 1147a8262c fix: 아이템 이름 오기 2022-08-28 15:41:50 +09:00
Hide_D 8a987cc55e fix: 조사 관련 문제 수정 2022-08-28 15:40:52 +09:00
Hide_D b28ca864f9 dep: package update 2022-08-28 15:30:35 +09:00
Hide_D 4bf77a5c55 game: 궁병 공격 시도, 추가페이즈 선제 공격
- 수비 선제와 구조적으로 동일
- 첫번째 상대에게 선제 사격
- 궁병과 궁병의 대결인 경우 항상 맞 선제 사격
2022-08-28 14:35:14 +09:00
Hide_D 4ebc20f182 game: 전투 첫 페이즈 계략시도 보정은 무장 제외 2022-08-28 14:17:09 +09:00
Hide_D 9eff1ccaed fix: 경매장 이름 풀 난수 생성기에 seed 초기화값 문제 수정 2022-08-27 12:15:12 +09:00
Hide_D 66170c98dd game: 수비 끔 시 사기 감소량 -3 => -6 2022-08-27 03:00:16 +09:00
Hide_D 397c054c66 game: 유니크 경매 제한 시간 감소
- 1분턴 마감시간 기준 1시간 -> 30분
2022-08-27 02:57:01 +09:00
Hide_D 0611551dc0 game: 의병모집 생성량 변경
- 3 + 연감 기준 평균 장수수 / 8 (반올림)
- 국가별 장수수가 평균 80명부터 역전
2022-08-27 02:46:44 +09:00
Hide_D 008f88d995 game: 전투시 얻는 기술량에서 공격자 상향
- 공격자 기술: 공격자가 입은 피해 * 0.012 (구 0.01)
- 수비자 기술: 수비자가 입은 피해 * 0.009 (구 0.01)
2022-08-27 02:39:47 +09:00
Hide_D 7fe450bc07 Revert "revert: LazyVarUpdater에 \BackedEnum 롤백"
This reverts commit a88ec71b44.
2022-08-26 22:16:06 +09:00
Hide_D a88ec71b44 revert: LazyVarUpdater에 \BackedEnum 롤백 2022-08-26 17:30:24 +09:00
Hide_D 8a5a3b67f7 refac: utilGame/getNPCColor 2022-08-26 01:06:43 +09:00
Hide_D 63771da876 misc: utilGame/index.ts 2022-08-26 00:34:56 +09:00
Hide_D 68891fafdb misc: CityColumn enum 2022-08-26 00:34:45 +09:00
Hide_D df31300a0b refac: GeneralBasicCard의 부대장 요구 정보를 간소화 2022-08-26 00:34:42 +09:00
Hide_D 16fb782bbf refac: LazyVarUpdater의 key로 BackedEnum 허용 2022-08-26 00:34:39 +09:00
Hide_D ed3e013a53 misc: GeneralColumn enum 추가 2022-08-26 00:34:32 +09:00
Hide_D 0bf568a655 feat: 국방 설정 시, 작성자와 작성 일시를 기록 2022-08-26 00:34:15 +09:00
Hide_D a5e481af96 fix: utilGame format에서 한단계 다르게 차이나는 버그 수정 2022-08-21 18:53:55 +09:00
Hide_D 78a9641c14 dep: lodash -> lodash-es 2022-08-21 18:14:36 +09:00
Hide_D b517000650 game: 성벽 공격 시 소모 쌀 20% 감소 2022-08-21 17:52:25 +09:00
Hide_D 1d20eb3c3e game: 초반 M장 생성 시 무지장 대량 생성 2022-08-21 17:42:33 +09:00
Hide_D 8248ccbcd5 game: 시간이 지남에 따라 성벽 강화
- 183년 기준 동일.
- 220년 기준 40% 전투력 상승
2022-08-20 15:03:58 +09:00
Hide_D b880b9bace game: NPC가 조금 더 상위병종을 시도할 확률을 높임 2022-08-20 14:39:51 +09:00
Hide_D 2da374410b game: 필살 계수 향상 방식 너프 2022-08-20 14:29:54 +09:00
Hide_D fff8f9493b game: 유니크 아이템 경매 시 현재가보다 1% 더 높아야 함 2022-08-20 14:15:49 +09:00
Hide_D 987baaa307 misc: 아시아 명장전 장수 구성 수정 2022-08-19 21:11:02 +09:00
Hide_D 9512ea9b52 feat: APICoveryType에 맞게 InvalidResponse 확장 2022-08-18 01:08:38 +09:00
Hide_D b0f3c1c97d feat: APIRecoveryType Enum 생성 2022-08-18 01:08:35 +09:00
Hide_D e823b97cf2 fix: 세션 관리 api 에러 2022-08-18 01:08:28 +09:00
Hide_D 203859ee5f dep: denque 추가 2022-08-16 23:58:21 +09:00
Hide_D 4870e2fa30 feat: GetRecentRecord 추가
- 메인페이지 최신 로그
2022-08-16 23:57:47 +09:00
Hide_D 970b702a2b fix: 빙의장은 제대로 유산을 받지 못하는 버그 수정 2022-08-13 03:18:31 +09:00
Hide_D 053288b227 fix: applyDB시 rankVarRead 처리 오류 (=은퇴 버그 수정)
- 은퇴는 applyDB 이후에 실행됨
- applyDB 코드 오류로 이후 key값 문제로 은퇴가 실행되지 않음
2022-08-13 03:12:09 +09:00
Hide_D e9b975bea7 fix: 의병모집에서 명성, 계급이 설정되지 않는 버그 수정 2022-08-12 02:25:12 +09:00
Hide_D 89fda44db8 game: 목우 상향, 무상성화 2022-08-10 23:53:19 +09:00
Hide_D fac8536095 fix: 도시 비중 계산식에서 '종사' 누락 2022-08-09 02:04:39 +09:00
Hide_D c79e65b6b7 misc: 아시아 명장전 유저장 스탯 수정 2022-08-08 21:38:02 +09:00
Hide_D 677e65ff6d dep: npm package update 2022-08-06 20:26:35 +09:00
Hide_D 0c7589d524 fix,misc: phan 검사 수준 복구 2022-08-05 23:45:31 +09:00
Hide_D da27ae2bad dep,refac: DTO를 composer 외부로 이동 2022-08-05 23:43:38 +09:00
Hide_D f8cd58bcb3 refac: conv_general_stat을 xlrd대신 opnepyxl로 변경
- 국가명 - 수뇌는 아직 테스트 안 해 보았음...
2022-08-03 00:53:41 +09:00
sarsandHide_D 3671a289b8 아시아 명장전 시나리오(비급) 추가 (#225)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/225
Reviewed-by: Hide_D <hided62@gmail.com>
Co-authored-by: sars <sarsntony@gmail.com>
Co-committed-by: sars <sarsntony@gmail.com>
2022-08-02 16:47:41 +09:00
Hide_D 48f4dbec50 misc: 부대편성 1000px 버튼의 위치를 명확히 2022-07-31 22:34:33 +09:00
Hide_D bdb29006e9 refac: 부대편성에서 1000px 모드 버튼을 좌하단으로 2022-07-31 22:20:29 +09:00
Hide_D 5ea324f103 fix: v-b-tooltip에서 undefined -> string type 초기화 생략 2022-07-31 20:34:18 +09:00
Hide_D 2f0cd32c18 fix: 부대 편성에서 부대장 집합 순서로 정렬 필요 2022-07-31 19:50:52 +09:00
Hide_D e8911d40df fix: 부대 편성에서 부대장과 다른 도시 표기가 안됨 2022-07-31 12:08:40 +09:00
Hide_D 89f173e7e3 fix: 베팅 최소 한도가 10이 아니라 1로 된 버그 수정 2022-07-30 21:13:00 +09:00
Hide_D b0ab3f6ace fix: css 누락, 로딩 누락 2022-07-30 20:48:31 +09:00
Hide_D 641af435d4 fix: 리셋 페이지 css 2022-07-30 20:45:27 +09:00
Hide_D 16a2f20af0 fix: 장수 카드에서 '남은 시간'이 제대로 표기 안됨 2022-07-30 20:16:08 +09:00
Hide_D 79734a6dcf fix: 부대명 변경이 아무에게나 보임 2022-07-30 19:44:30 +09:00
Hide_D 2e2ff1b150 feat: 감찰부에서 '이전', '다음' 버튼 2022-07-30 19:34:34 +09:00
Hide_D 5ce899ee6e fix: 장수 카드에 부상스탯 미반영 2022-07-30 14:25:23 +09:00
Hide_D e041080773 fix: 유산 포인트가 0이어도 동작 2022-07-30 12:15:07 +09:00
Hide_D f8448fbb51 fix: 자동 해산에 필요한 변수를 제공하지 않음 2022-07-30 10:34:40 +09:00
Hide_D 8defcd29a4 fix: 인자 오류 수정 2022-07-30 10:31:31 +09:00
Hide_D fba60df9d1 fix: binarysearch 상한 에러 2022-07-29 01:24:09 +09:00
Hide_D a4ff1f44ba build: source-map 활성화(디버그용) 2022-07-29 01:13:51 +09:00
230 changed files with 9523 additions and 4800 deletions
+2
View File
@@ -10,8 +10,10 @@
*.log
logs/*.txt
api_log.db
d_log/*.txt
d_log/*.zip
d_log/*.db
sess_*
*/logs/*.txt
*/logs/*/*.txt
-7
View File
@@ -98,12 +98,6 @@ return [
'hwe/j_load_scenarios.php',
'hwe/j_map.php',
'hwe/j_map_recent.php',
'hwe/j_msg_contact_list.php',
'hwe/j_msg_decide_opt.php',
'hwe/j_msg_delete.php',
'hwe/j_msg_get_old.php',
'hwe/j_msg_get_recent.php',
'hwe/j_msg_submit.php',
'hwe/j_myBossInfo.php',
'hwe/j_raise_event.php',
'hwe/j_select_npc.php',
@@ -112,7 +106,6 @@ return [
'hwe/j_set_my_setting.php',
'hwe/j_set_npc_control.php',
'hwe/j_simulate_battle.php',
'hwe/j_troop.php',
'hwe/j_update_picked_general.php',
'hwe/j_vacation.php',
'hwe/lib.php',
+3 -3
View File
@@ -17,7 +17,6 @@
"league/plates": "^3.3",
"vlucas/valitron": "^1.4",
"php-extended/php-tail": "^2.1",
"pguardiario/phpuri": "^1.0",
"symfony/lock": "^6.0",
"ezyang/htmlpurifier": "^4.10",
"xemlock/htmlpurifier-html5": "^0.1.7",
@@ -26,8 +25,9 @@
"nette/caching": "^3.0",
"illuminate/database": "^9.12",
"illuminate/events": "^9.12",
"spatie/data-transfer-object": "^3.7",
"php-ds/php-ds": "^1.4"
"php-ds/php-ds": "^1.4",
"hided62/ldto": "^1.0",
"league/uri": "^6.8"
},
"autoload": {
"psr-4": {
Generated
+280 -93
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "908099160e2765c04448fef3f35794c4",
"content-hash": "d7acaa437c3c6f48c9a643c9dc4ef421",
"packages": [
{
"name": "brandonwamboldt/utilphp",
@@ -537,6 +537,60 @@
},
"time": "2021-06-11T22:34:44+00:00"
},
{
"name": "hided62/ldto",
"version": "v1.0.0",
"source": {
"type": "git",
"url": "https://github.com/hided62/ldto.git",
"reference": "4c05401406f8afc1636a90763c13884f8fff0d14"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hided62/ldto/zipball/4c05401406f8afc1636a90763c13884f8fff0d14",
"reference": "4c05401406f8afc1636a90763c13884f8fff0d14",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"require-dev": {
"phan/phan": "^5.3",
"phpunit/phpunit": "^9.5"
},
"type": "library",
"autoload": {
"psr-4": {
"LDTO\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Hide_D",
"email": "hided62@gmail.com",
"homepage": "https://hided.net",
"role": "Developer"
}
],
"description": "php lightweight dto library",
"homepage": "https://github.com/hided62/ldto",
"keywords": [
"data-transfer-object",
"dto",
"hided62",
"lightweight",
"serialize"
],
"support": {
"issues": "https://github.com/hided62/ldto/issues",
"source": "https://github.com/hided62/ldto/tree/v1.0.0"
},
"time": "2022-08-05T14:30:13+00:00"
},
{
"name": "illuminate/bus",
"version": "v9.12.2",
@@ -1140,6 +1194,177 @@
},
"time": "2020-12-25T05:00:37+00:00"
},
{
"name": "league/uri",
"version": "6.8.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/uri.git",
"reference": "a700b4656e4c54371b799ac61e300ab25a2d1d39"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/uri/zipball/a700b4656e4c54371b799ac61e300ab25a2d1d39",
"reference": "a700b4656e4c54371b799ac61e300ab25a2d1d39",
"shasum": ""
},
"require": {
"ext-json": "*",
"league/uri-interfaces": "^2.3",
"php": "^8.1",
"psr/http-message": "^1.0.1"
},
"conflict": {
"league/uri-schemes": "^1.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^v3.9.5",
"nyholm/psr7": "^1.5.1",
"php-http/psr7-integration-tests": "^1.1.1",
"phpbench/phpbench": "^1.2.6",
"phpstan/phpstan": "^1.8.5",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-phpunit": "^1.1.1",
"phpstan/phpstan-strict-rules": "^1.4.3",
"phpunit/phpunit": "^9.5.24",
"psr/http-factory": "^1.0.1"
},
"suggest": {
"ext-fileinfo": "Needed to create Data URI from a filepath",
"ext-intl": "Needed to improve host validation",
"league/uri-components": "Needed to easily manipulate URI objects",
"psr/http-factory": "Needed to use the URI factory"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.x-dev"
}
},
"autoload": {
"psr-4": {
"League\\Uri\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ignace Nyamagana Butera",
"email": "nyamsprod@gmail.com",
"homepage": "https://nyamsprod.com"
}
],
"description": "URI manipulation library",
"homepage": "https://uri.thephpleague.com",
"keywords": [
"data-uri",
"file-uri",
"ftp",
"hostname",
"http",
"https",
"middleware",
"parse_str",
"parse_url",
"psr-7",
"query-string",
"querystring",
"rfc3986",
"rfc3987",
"rfc6570",
"uri",
"uri-template",
"url",
"ws"
],
"support": {
"docs": "https://uri.thephpleague.com",
"forum": "https://thephpleague.slack.com",
"issues": "https://github.com/thephpleague/uri/issues",
"source": "https://github.com/thephpleague/uri/tree/6.8.0"
},
"funding": [
{
"url": "https://github.com/sponsors/nyamsprod",
"type": "github"
}
],
"time": "2022-09-13T19:58:47+00:00"
},
{
"name": "league/uri-interfaces",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/uri-interfaces.git",
"reference": "00e7e2943f76d8cb50c7dfdc2f6dee356e15e383"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/00e7e2943f76d8cb50c7dfdc2f6dee356e15e383",
"reference": "00e7e2943f76d8cb50c7dfdc2f6dee356e15e383",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "^7.2 || ^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.19",
"phpstan/phpstan": "^0.12.90",
"phpstan/phpstan-phpunit": "^0.12.19",
"phpstan/phpstan-strict-rules": "^0.12.9",
"phpunit/phpunit": "^8.5.15 || ^9.5"
},
"suggest": {
"ext-intl": "to use the IDNA feature",
"symfony/intl": "to use the IDNA feature via Symfony Polyfill"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"League\\Uri\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ignace Nyamagana Butera",
"email": "nyamsprod@gmail.com",
"homepage": "https://nyamsprod.com"
}
],
"description": "Common interface for URI representation",
"homepage": "http://github.com/thephpleague/uri-interfaces",
"keywords": [
"rfc3986",
"rfc3987",
"uri",
"url"
],
"support": {
"issues": "https://github.com/thephpleague/uri-interfaces/issues",
"source": "https://github.com/thephpleague/uri-interfaces/tree/2.3.0"
},
"funding": [
{
"url": "https://github.com/sponsors/nyamsprod",
"type": "github"
}
],
"time": "2021-06-28T04:27:21+00:00"
},
{
"name": "microsoft/tolerant-php-parser",
"version": "v0.1.1",
@@ -1556,34 +1781,6 @@
},
"time": "2022-01-24T11:29:14+00:00"
},
{
"name": "pguardiario/phpuri",
"version": "1.0",
"source": {
"type": "git",
"url": "https://github.com/monkeysuffrage/phpuri.git",
"reference": "ad0a5ec033fe616cfef55578b9c7f2458be8fbfc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/monkeysuffrage/phpuri/zipball/ad0a5ec033fe616cfef55578b9c7f2458be8fbfc",
"reference": "ad0a5ec033fe616cfef55578b9c7f2458be8fbfc",
"shasum": ""
},
"type": "project",
"autoload": {
"files": [
"phpuri.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"description": "A php library for converting relative urls to absolute.",
"support": {
"issues": "https://github.com/monkeysuffrage/phpuri/issues",
"source": "https://github.com/monkeysuffrage/phpuri/tree/1.0.0"
},
"time": "2015-05-24T09:13:17+00:00"
},
{
"name": "phan/phan",
"version": "5.3.2",
@@ -2023,6 +2220,59 @@
},
"time": "2021-11-05T16:47:00+00:00"
},
{
"name": "psr/http-message",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/master"
},
"time": "2016-08-06T14:39:51+00:00"
},
{
"name": "psr/log",
"version": "3.0.0",
@@ -2238,69 +2488,6 @@
},
"time": "2021-06-29T04:31:23+00:00"
},
{
"name": "spatie/data-transfer-object",
"version": "3.7.3",
"source": {
"type": "git",
"url": "https://github.com/spatie/data-transfer-object.git",
"reference": "341f72c77e0fce40ea2e0dcb212cb54dc27bbe72"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/data-transfer-object/zipball/341f72c77e0fce40ea2e0dcb212cb54dc27bbe72",
"reference": "341f72c77e0fce40ea2e0dcb212cb54dc27bbe72",
"shasum": ""
},
"require": {
"php": "^8.0"
},
"require-dev": {
"illuminate/collections": "^8.36",
"jetbrains/phpstorm-attributes": "^1.0",
"larapack/dd": "^1.1",
"phpunit/phpunit": "^9.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\DataTransferObject\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Brent Roose",
"email": "brent@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Data transfer objects with batteries included",
"homepage": "https://github.com/spatie/data-transfer-object",
"keywords": [
"data-transfer-object",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/data-transfer-object/issues",
"source": "https://github.com/spatie/data-transfer-object/tree/3.7.3"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2021-12-30T20:31:10+00:00"
},
{
"name": "symfony/console",
"version": "v6.0.8",
@@ -5337,5 +5524,5 @@
"platform-overrides": {
"php": "8.1"
},
"plugin-api-version": "2.2.0"
"plugin-api-version": "2.3.0"
}
BIN
View File
Binary file not shown.
+4 -4
View File
@@ -90,19 +90,19 @@ if (
//기본 파일 생성
if (!file_exists(AppConf::getUserIconPathFS())) {
mkdir(AppConf::getUserIconPathFS());
mkdir(AppConf::getUserIconPathFS(), 0775);
}
if (!file_exists(ROOT . '/d_log')) {
mkdir(ROOT . '/d_log');
mkdir(ROOT . '/d_log', 0775);
}
if (!file_exists(ROOT . '/d_setting')) {
mkdir(ROOT . '/d_setting');
mkdir(ROOT . '/d_setting', 0775);
}
if (!file_exists(ROOT . '/d_shared')) {
mkdir(ROOT . '/d_shared');
mkdir(ROOT . '/d_shared', 0775);
}
}
+17
View File
@@ -0,0 +1,17 @@
CREATE TABLE IF NOT EXISTS "api_log" (
"id" INTEGER NOT NULL,
"user_id" INTEGER NOT NULL,
"ip" TEXT NOT NULL,
"date" TEXT NOT NULL,
"path" TEXT NOT NULL,
"arg" TEXT,
"aux" TEXT,
PRIMARY KEY("id" AUTOINCREMENT)
);
CREATE INDEX IF NOT EXISTS "by_date" ON "api_log" (
"date" DESC
);
CREATE INDEX IF NOT EXISTS "by_user" ON "api_log" (
"user_id" ASC,
"date" DESC
);
-2
View File
@@ -40,8 +40,6 @@ $admin = getAdmin();
<tr>
<td width=110 align=right>시작시간변경</td>
<td width=285><input type=text size=20 maxlength=20 style=color:white;background-color:black;text-align:right; name=starttime value='<?=substr($admin['starttime'], 0, 19)?>'><input type=submit name=btn value=변경1></td>
<td width=110 align=right>현재도시훈사</td>
<td width=285><?=$admin['city_rate']?></td>
</tr>
<tr>
<td width=110 align=right>최대 장수</td>
+10 -8
View File
@@ -2,6 +2,8 @@
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
@@ -111,7 +113,7 @@ switch ($btn) {
case "경험치1000":
$text = $btn . " 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -122,7 +124,7 @@ switch ($btn) {
case "공헌치1000":
$text = $btn . " 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -133,7 +135,7 @@ switch ($btn) {
case "보숙10000":
$text = "보병숙련도+10000 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -143,7 +145,7 @@ switch ($btn) {
case "궁숙10000":
$text = "궁병숙련도+10000 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -154,7 +156,7 @@ switch ($btn) {
$src = MessageTarget::buildQuick($session->generalID);
$text = "기병숙련도+10000 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -165,7 +167,7 @@ switch ($btn) {
$src = MessageTarget::buildQuick($session->generalID);
$text = "귀병숙련도+10000 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -176,7 +178,7 @@ switch ($btn) {
$src = MessageTarget::buildQuick($session->generalID);
$text = "차병숙련도+10000 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -196,7 +198,7 @@ switch ($btn) {
case "메세지 전달":
$text = $msg ?? '';
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
break;
+4 -2
View File
@@ -2,6 +2,8 @@
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
//로그인 검사
@@ -18,7 +20,7 @@ $msg = Util::getPost('msg', 'string', '메시지');
$db = DB::db();
//NOTE: 왜 기능이 admin2와 admin4가 같이 있는가?
//NOTE: 왜 기능이 admin2와 admin4가 같이 있는가?
//NOTE: 왜 블럭 시 admin4에선 금쌀을 없애지 않는가?
switch ($btn) {
case "블럭 해제":
@@ -66,7 +68,7 @@ switch ($btn) {
$src = MessageTarget::buildQuick($session->generalID);
foreach($genlist as $generalID){
$msgObj = new Message(
Message::MSGTYPE_PRIVATE,
MessageType::private,
$src,
MessageTarget::buildQuick($generalID),
$msg,
+1 -2
View File
@@ -27,7 +27,6 @@ foreach ($db->queryFirstColumn(
$inheritPointManager = InheritancePointManager::getInstance();
foreach(General::createGeneralObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc = 0')) as $genObj){
$inheritPointManager->mergeTotalInheritancePoint($genObj, true);
$inheritPointManager->mergeTotalInheritancePoint($genObj);
$inheritPointManager->applyInheritanceUser($genObj->getVar('owner'));
$inheritPointManager->clearInheritancePoint($genObj);
}
+1 -1
View File
@@ -8,7 +8,7 @@ include "func.php";
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
increaseRefresh("갱신정보", 2);
increaseRefresh("갱신정보", 1);
$admin = $gameStor->getValues(['year', 'month', 'refresh', 'maxrefresh', 'maxonline']);
+2 -2
View File
@@ -29,7 +29,7 @@ if ($myset > 0) {
$submit = 'hidden';
}
$targetTime = addTurn($me->getVar('lastrefresh'), $gameStor->turnterm, 2);
$targetTime = addTurn($me->getVar('lastrefresh'), $gameStor->turnterm, GameConst::$minTurnDieOnPrestart);
if ($gameStor->turntime <= $gameStor->opentime) {
//서버 가오픈시 할 수 있는 행동
if ($me->getNPCType() == 0 && $me->getNationID() == 0) {
@@ -116,7 +116,7 @@ $use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn') ?? 1;
<?php foreach ([90, 80, 60, 40] as $targetDefenceTrain) : ?>
<option value='<?= $targetDefenceTrain ?>' <?= $me->getVar('defence_train') == $targetDefenceTrain ? "selected" : ""; ?>><?= formatDefenceTrain($targetDefenceTrain) ?>(훈사<?= $targetDefenceTrain ?>)</option>
<?php endforeach; ?>
<option value=999 <?= $me->getVar('defence_train') == 999 ? "selected" : ""; ?>><?= formatDefenceTrain(999) ?>[훈련, 사기 -3]</option>
<option value=999 <?= $me->getVar('defence_train') == 999 ? "selected" : ""; ?>><?= formatDefenceTrain(999) ?>[훈련 -3, 사기 -6]</option>
</select>
】<br><br>
<input type=<?= $submit ?> id='set_my_setting' name=btn style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px; value=설정저장><br>
+30 -3
View File
@@ -65,8 +65,8 @@ if ($nationID) {
전역 설정
</div>
<div class="card-body dragpad_battle">
<div class="row">
<div class="col-sm-6">
<div class="row gx-0">
<div class="col-sm-4">
<div class="input-group">
<input type="number" class="form-control" aria-describedby="text_year" value="<?= $startYear ?>" disabled>
<div class="input-group-text"> 년 시작 </div>
@@ -76,9 +76,13 @@ if ($nationID) {
<div class="input-group-text"> 월 </div>
</div>
</div>
<div class="col-sm-6">
<div class="col-sm-5 px-2">
<div class="btn-toolbar" role="toolbar">
<div class="input-group me-2" role="group">
<div class="input-group-text">
시드
</div>
<input type="text" class="form-control" id="seed" aria-describedby="text_seed">
<div class="input-group-text">
반복 횟수
</div>
@@ -87,6 +91,10 @@ if ($nationID) {
<option value="1000">1000회 (요약 표기)</option>
</select>
</div>
</div>
</div>
<div class="col-sm-3">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group me-2" role="group">
<button type="button" class="btn btn-danger btn-begin_battle">전투</button>
</div>
@@ -426,6 +434,25 @@ if ($nationID) {
</div>
<input type="number" class="form-control form_killcrew" value="0" step="1">
</div>
<div class="input-group mb-0">
<div class="input-group-text">자신</div>
<div class="input-group-text">회피 확률</div>
<input type="number" class="form-control form_war_avoid_ratio" value="0" step="1" min="0" max="5">
<div class="input-group-text">필살 확률</div>
<input type="number" class="form-control form_war_critical_ratio" value="0" step="1" min="0" max="5">
<div class="input-group-text">계략 시도 확률</div>
<input type="number" class="form-control form_war_magic_trial_prob" value="0" step="1" min="0" max="5">
</div>
<div class="input-group mb-1">
<div class="input-group-text">상대</div>
<div class="input-group-text">회피 확률</div>
<input type="number" class="form-control form_oppose_war_avoid_ratio" value="0" step="1" min="0" max="5">
<div class="input-group-text">필살 확률</div>
<input type="number" class="form-control form_oppose_war_critical_ratio" value="0" step="1" min="0" max="5">
<div class="input-group-text">계략 시도 확률</div>
<input type="number" class="form-control form_oppose_war_magic_trial_prob" value="0" step="1" min="0" max="5">
</div>
</div>
</div>
+40 -61
View File
@@ -886,7 +886,7 @@ function generalInfo2(General $generalObj)
function getOnlineNum(): int
{
return KVStorage::getStorage(DB::db(), 'game_env')->getValue('online') ?? 0;
return KVStorage::getStorage(DB::db(), 'game_env')->getValue('online_user_cnt') ?? 0;
}
function onlinegen(General $general)
@@ -906,7 +906,7 @@ function nationMsg(General $general)
$nationID = $general->getNationID();
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
return $nationStor->notice ?? '';
return $nationStor->nationNotice['msg'] ?? '';
}
function banner()
@@ -1003,19 +1003,31 @@ function increaseRefresh($type = "", $cnt = 1)
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->refresh = $gameStor->refresh + $cnt; //TODO: +로 증가하는 값은 별도로 분리
$isunited = $gameStor->isunited;
$opentime = $gameStor->opentime;
if ($isunited != 2 && $generalID && $userGrade < 6 && $opentime <= TimeUtil::now()) {
$db->update('general', [
'lastrefresh' => $date,
'con' => $db->sqleval('con + %i', $cnt),
'connect' => $db->sqleval('connect + %i', $cnt),
'refcnt' => $db->sqleval('refcnt + %i', $cnt),
'refresh' => $db->sqleval('refresh + %i', $cnt)
], 'owner=%i', $userID);
if($userGrade == 6){
return;
}
if($isunited == 2){
return;
}
if(!$generalID){
return;
}
if($opentime > $date){
return;
}
$gameStor->refresh = $gameStor->refresh + $cnt; //TODO: +로 증가하는 값은 별도로 분리
$db->update('general', [
'lastrefresh' => $date,
'con' => $db->sqleval('con + %i', $cnt),
'connect' => $db->sqleval('connect + %i', $cnt),
'refcnt' => $db->sqleval('refcnt + %i', $cnt),
'refresh' => $db->sqleval('refresh + %i', $cnt)
], 'owner=%i', $userID);
$date = date('Y_m_d H:i:s');
$date2 = substr($date, 0, 10);
@@ -1033,42 +1045,6 @@ function increaseRefresh($type = "", $cnt = 1)
),
FILE_APPEND
);
$proxy_headers = array(
'HTTP_VIA',
'HTTP_X_FORWARDED_FOR',
'HTTP_FORWARDED_FOR',
'HTTP_X_FORWARDED',
'HTTP_FORWARDED',
'HTTP_CLIENT_IP',
'HTTP_FORWARDED_FOR_IP',
'VIA',
'X_FORWARDED_FOR',
'FORWARDED_FOR',
'X_FORWARDED',
'FORWARDED',
'CLIENT_IP',
'FORWARDED_FOR_IP',
'HTTP_PROXY_CONNECTION'
);
$str = "";
foreach ($proxy_headers as $x) {
if (isset($_SERVER[$x])) $str .= "//{$x}:{$_SERVER[$x]}";
}
if ($str != "") {
file_put_contents(
__DIR__ . "/logs/" . UniqueConst::$serverID . "/_{$date2}_ipcheck.txt",
sprintf(
"%s, %s, %s%s\n",
$session->userName,
$session->generalName,
$_SERVER['REMOTE_ADDR'],
$str
),
FILE_APPEND
);
}
}
function updateTraffic()
@@ -1223,10 +1199,9 @@ function updateOnline()
$nationname[$nation['nation']] = $nation['name'];
}
//동접수
$before5Min = TimeUtil::nowAddMinutes(-5);
$onlineUser = $db->query('SELECT no,name,nation FROM general WHERE lastrefresh > %s AND npc < 2', $before5Min);
$startTurn = cutTurn($gameStor->turntime, $gameStor->turnterm, false);
$onlineUser = $db->query('SELECT no,name,nation FROM general WHERE lastrefresh >= %s AND npc < 2', $startTurn);
$onlineNum = count($onlineUser);
$onlineNationUsers = Util::arrayGroupBy($onlineUser, 'nation');
@@ -1745,7 +1720,8 @@ function tryUniqueItemLottery(RandUtil $rng, General $general, string $acquireTy
$prob = 1 / ($genCount * $itemTypeCnt / 10 / 4); // 건국시 4개(20%) 등장(200명시 20국 정도 됨)
}
$prob = Util::valueFit($prob, null, 1 / 4); //최대치 감소
$prob *= GameConst::$uniqueTrialCoef;
$prob = Util::valueFit($prob, null, GameConst::$maxUniqueTrialProb); //최대치 감소
$result = false;
$prob /= sqrt(7);
@@ -1805,16 +1781,16 @@ function deleteNation(General $lord, bool $applyDB): array
$nationID,
$lordID
),
['npc', 'gold', 'rice', 'experience', 'explevel', 'dedication', 'dedlevel', 'belong', 'aux'],
['npc', 'owner', 'gold', 'rice', 'experience', 'explevel', 'dedication', 'dedlevel', 'belong', 'aux'],
1
);
$nationGeneralList[$lordID] = $lord;
$nation['generals'] = array_keys($nationGeneralList);
$nation['aux'] = Json::decode($nation['aux']);
$nation['msg'] = $nationStor->notice;
$nation['msg'] = $nationStor->nationNotice['msg'] ?? '';
$nation['scout_msg'] = $nationStor->scout_msg;
$nation['aux'] += $nationStor->max_power;
$nation['aux'] += $nationStor->max_power ?? [];
$nation['history'] = getNationHistoryLogAll($nationID);
$josaYi = JosaUtil::pick($nationName, '이');
@@ -1823,13 +1799,16 @@ function deleteNation(General $lord, bool $applyDB): array
// 전 장수 재야로
foreach ($nationGeneralList as $general) {
$general->setAuxVar(
InheritanceKey::max_belong->value,
max(
$general->getVar('belong'),
$general->getAuxVar(InheritanceKey::max_belong->value) ?? 0
)
);
if($general->getNPCType() < 2){
$general->setAuxVar(
InheritanceKey::max_belong->value,
max(
$general->getVar('belong'),
$general->getAuxVar(InheritanceKey::max_belong->value) ?? 0
)
);
}
$general->setVar('belong', 0);
$general->setVar('troop', 0);
$general->setVar('officer_level', 0);
+59 -44
View File
@@ -285,13 +285,8 @@ function preUpdateMonthly()
'rate_tmp' => $db->sqleval('rate')
], true);
//도시훈사 180년 60, 220년 87, 240년 100
$rate = Util::round(($admin['year'] - $admin['startyear']) / 1.5) + 60;
if ($rate > 100) $rate = 100;
// 20 ~ 140원
$develcost = ($admin['year'] - $admin['startyear'] + 10) * 2;
$gameStor->city_rate = $rate;
$gameStor->develcost = $develcost;
//매달 사망자 수입 결산
@@ -528,7 +523,7 @@ function checkWander(RandUtil $rng)
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['year', 'month']);
$admin = $gameStor->getValues(['year', 'month', 'init_year', 'init_month']);
$wanderers = $db->queryFirstColumn('SELECT general.`no` FROM general LEFT JOIN nation ON general.nation = nation.nation WHERE nation.`level` = 0 AND general.`officer_level` = 12');
@@ -559,32 +554,39 @@ function updateNationState()
$startYear = $admin['startyear'];
$assemblerCnts = [];
$nationCityCounts = [];
foreach($db->queryAllLists('SELECT nation, count(*) FROM city WHERE LEVEL>=4 GROUP BY nation') as [$nationID, $cityCnt]){
$nationCityCounts[$nationID] = $cityCnt;
}
foreach ($db->queryAllLists('SELECT nation,count(no) FROM general WHERE npc = 5 GROUP BY nation') as [$nationID, $assemblerCnt]) {
$assemblerCnts[$nationID] = $assemblerCnt;
};
$nationLevelByCityCnt = [
0, //방랑군
1, //호족
2, //군벌
5, //주자사
8, //주목
11, //공
16, //왕
21, //황제
];
foreach ($db->query('SELECT nation,name,level,tech,aux FROM nation') as $nation) {
//TODO: level이 진관수이소중대특 체계를 벗어날 수 있음
$nationID = $nation['nation'];
$citycount = $db->queryFirstField('SELECT count(*) FROM city WHERE nation=%i AND level>=4', $nationID);
$cityCnt = $nationCityCounts[$nationID] ?? 0;
if ($citycount == 0) {
$nationlevel = 0; // 방랑군
} elseif ($citycount == 1) {
$nationlevel = 1; // 호족
} elseif ($citycount <= 4) {
$nationlevel = 2; // 군벌
} elseif ($citycount <= 7) {
$nationlevel = 3; // 주자사
} elseif ($citycount <= 10) {
$nationlevel = 4; // 주목
} elseif ($citycount <= 15) {
$nationlevel = 5; // 공
} elseif ($citycount <= 20) {
$nationlevel = 6; // 왕
} else {
$nationlevel = 7; // 황제
/** @var int */
$nationlevel = 0;
foreach($nationLevelByCityCnt as $cmpNationLevel => $cmpCityCnt){
if($cityCnt < $cmpCityCnt){
break;
}
$nationlevel = $cmpNationLevel;
}
if ($nationlevel > $nation['level']) {
@@ -598,33 +600,47 @@ function updateNationState()
'rice' => $db->sqleval('rice + %i', $nationlevel * 1000),
];
$nationName = $nation['name'];
$lordName = $db->queryFirstField('SELECT name FROM general WHERE nation = %i AND officer_level = 12', $nationID);
$oldNationLevelText = getNationLevel($oldLevel);
$nationLevelText = getNationLevel($nationlevel);
$logger = new ActionLogger(0, $nationID, $year, $month, false);
$josaYi = JosaUtil::pick($lordName, '이');
switch ($nationlevel) {
case 7:
$josaUl = JosaUtil::pick(getNationLevel($nationlevel), '');
$history[] = "<C>●</>{$year}{$month}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>{$josaUl} 자칭하였습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$year}{$month}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>{$josaUl} 자칭"]);
case 7: //황제
$josaRo = JosaUtil::pick($nationLevelText, '');
$logger->pushGlobalHistoryLog("<Y><b>【작위】</b></><D><b>{$nationName}</b></> {$oldNationLevelText} <Y>{$lordName}</>{$josaYi} <C>{$nationLevelText}</>{$josaRo} 옹립되었습니다.");
$logger->pushNationalHistoryLog("<D><b>{$nationName}</b></> {$oldNationLevelText} <Y>{$lordName}</>{$josaYi} <C>{$nationLevelText}</>{$josaRo} 옹립");
$auxVal = Json::decode($nation['aux']);
$auxVal['can_국기변경'] = 1;
$auxVal['can_국호변경'] = 1;
$updateVals['aux'] = Json::encode($auxVal);
break;
case 6:
$history[] = "<C>●</>{$year}{$month}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 등극하였습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$year}{$month}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 등극"]);
case 6: //왕
$josaRo = JosaUtil::pick($nationLevelText, '로');
$logger->pushGlobalHistoryLog("<Y><b>【작위】</b></><D><b>{$nationName}</b></>의 <Y>{$lordName}</>{$josaYi} <C>$nationLevelText</>{$josaRo} 책봉되었습니다.");
$logger->pushNationalHistoryLog("<D><b>{$nationName}</b></>의 <Y>{$lordName}</>{$josaYi} <C>$nationLevelText</>{$josaRo} 책봉");
break;
case 5:
case 4:
case 3:
$history[] = "<C>●</>{$year}{$month}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 임명되었습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$year}{$month}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 임명됨"]);
case 5: //공
case 4: //주목
case 3: //주자사
$josaRo = JosaUtil::pick($nationLevelText, '로');
$logger->pushGlobalHistoryLog("<Y><b>【작위】</b></><D><b>{$nationName}</b></>의 <Y>{$lordName}</>{$josaYi} <C>$nationLevelText</>{$josaRo} 임명되었습니다.");
$logger->pushNationalHistoryLog("<D><b>{$nationName}</b></>의 <Y>{$lordName}</>{$josaYi} <C>$nationLevelText</>{$josaRo} 임명됨");
break;
case 2:
$history[] = "<C>●</>{$year}{$month}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 독립하여 <Y>" . getNationLevel($nationlevel) . "</>로 나섰습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$year}{$month}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>로 나서다"]);
case 2: //군벌
$josaRa = JosaUtil::pick($nationName, '라');
$josaRo = JosaUtil::pick($nationLevelText, '로');
$logger->pushGlobalHistoryLog("<Y><b>【작위】</b></><Y>{$lordName}</>{$josaYi} 독립하여 <D><b>{$nationName}</b></>{$josaRa}는 <C>$nationLevelText</>{$josaRo} 나섰습니다.");
$logger->pushNationalHistoryLog("<Y>{$lordName}</>{$josaYi} 독립하여 <D><b>{$nationName}</b></>{$josaRa}는 <C>$nationLevelText</>{$josaRo} 나서다");
break;
}
$db->update('nation', $updateVals, 'nation=%i', $nation['nation']);
$logger->flush();
$turnRows = [];
foreach (Util::range(getNationChiefLevel($nation['level']), 12) as $chiefLevel) {
@@ -1076,9 +1092,8 @@ function checkEmperior()
}
processSumInheritPointRank();
foreach ($allUserGenerals as $genObj) {
$inheritPointManager->mergeTotalInheritancePoint($genObj, true);
$inheritPointManager->mergeTotalInheritancePoint($genObj);
$inheritPointManager->applyInheritanceUser($genObj->getVar('owner'));
$inheritPointManager->clearInheritancePoint($genObj);
}
$gameStor->isunited = 2;
@@ -1147,9 +1162,9 @@ function checkEmperior()
$nation = $nation;
$nation['generals'] = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=%i', $nation['nation']);
$nation['aux'] = Json::decode($nation['aux']);
$nation['msg'] = $nationStor->notice;
$nation['msg'] = $nationStor->nationNotice['msg'] ?? '';;
$nation['scout_msg'] = $nationStor->scout_msg;
$nation['aux'] += $nationStor->max_power;
$nation['aux'] += $nationStor->max_power ?? [];
$nation['history'] = getNationHistoryLogAll($nation['nation']);
storeOldGenerals(0, $admin['year'], $admin['month']);
@@ -1226,7 +1241,7 @@ function checkEmperior()
]);
$hiddenSeed = UniqueConst::$hiddenSeed;
$history = ["<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【통일】</b></><D><b>{$nation['name']}</b></>{$josaYi} 전토를 통일하였습니다. <span class='hidden_but_copyable'>(서버시드: $hiddenSeed})</span>"];
$history = ["<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【통일】</b></><D><b>{$nation['name']}</b></>{$josaYi} 전토를 통일하였습니다. <span class='hidden_but_copyable'>(서버시드: {$hiddenSeed})</span>"];
pushGlobalHistoryLog($history, $admin['year'], $admin['month']);
//연감 월결산
+12 -10
View File
@@ -32,6 +32,7 @@ if ($session->userGrade < 5 && !$allowReset) {
<meta name="viewport" content="width=device-width, initial-scale=1" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printCSS('css/install.css') ?>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common', 'install']) ?>
</head>
@@ -92,8 +93,8 @@ if ($session->userGrade < 5 && !$allowReset) {
<label for="fiction" class="col-sm-3 col-form-label">NPC 상성</label>
<div class="col-sm-9">
<div id="fiction" class="btn-group btn-group-toggle" data-bs-toggle="buttons">
<input type="radio" id="fiction_0" class="btn-check" name="fiction" value="0" checked><label for="fiction_0" class="btn btn-secondary"> 연의 </label>
<input type="radio" id="fiction_1" class="btn-check" name="fiction" value="1"><label for="fiction_1" class="btn btn-secondary"> 가상 </label>
<input type="radio" id="fiction_0" class="btn-check" name="fiction" value="0"><label for="fiction_0" class="btn btn-secondary"> 연의 </label>
<input type="radio" id="fiction_1" class="btn-check" name="fiction" value="1" checked><label for="fiction_1" class="btn btn-secondary"> 가상 </label>
</div>
</div>
</div>
@@ -113,6 +114,7 @@ if ($session->userGrade < 5 && !$allowReset) {
<div class="col-sm-9">
<div id="block_general_create" class="btn-group btn-group-toggle" data-bs-toggle="buttons">
<input type="radio" class="btn-check" id="block_general_create_0" name="block_general_create" value="0" checked><label for="block_general_create_0" class="btn btn-secondary">가능</label>
<input type="radio" class="btn-check" id="block_general_create_2" name="block_general_create" value="2"><label for="block_general_create_2" class="btn btn-secondary">장수명무작위</label>
<input type="radio" class="btn-check" id="block_general_create_1" name="block_general_create" value="1"><label for="block_general_create_1" class="btn btn-secondary">불가</label>
</div>
</div>
@@ -134,13 +136,13 @@ if ($session->userGrade < 5 && !$allowReset) {
<div class="col-sm-9">
<div class="input-group">
<div class="btn-group btn-group-toggle" data-bs-toggle="buttons">
<input type="checkbox" id="autorun_develop" class="autorun_user_chk btn-check" data-key="develop" name="autorun_user[]" value="develop"><label class="btn btn-secondary" for="autorun_develop">내정</label>
<input type="checkbox" id="autorun_warp" class="autorun_user_chk btn-check" data-key="warp" name="autorun_user[]" value="warp"><label class="btn btn-secondary" for="autorun_warp">순간이동</label>
<input type="checkbox" id="autorun_recruit" class="autorun_user_chk btn-check" data-key="recruit" name="autorun_user[]" value="recruit"><label class="btn btn-secondary" for="autorun_recruit">징병</label>
<input type="checkbox" id="autorun_recruit_high" class="autorun_user_chk btn-check" data-key="recruit_high" name="autorun_user[]" value="recruit_high"><label class="btn btn-secondary" for="autorun_recruit_high">모병</label>
<input type="checkbox" id="autorun_train" class="autorun_user_chk btn-check" data-key="train" name="autorun_user[]" value="train"><label class="btn btn-secondary" for="autorun_train">훈사</label>
<input type="checkbox" id="autorun_battle" class="autorun_user_chk btn-check" data-key="battle" name="autorun_user[]" value="battle"><label class="btn btn-secondary" for="autorun_battle">출병</label>
<input type="checkbox" id="autorun_chief" class="autorun_user_chk btn-check" data-key="chief" name="autorun_user[]" value="chief"><label class="btn btn-secondary" for="autorun_chief">기본 사령턴</label>
<input type="checkbox" id="autorun_develop" class="autorun_user_chk btn-check" data-key="develop" name="autorun_user[]" value="develop" checked><label class="btn btn-secondary" for="autorun_develop">내정</label>
<input type="checkbox" id="autorun_warp" class="autorun_user_chk btn-check" data-key="warp" name="autorun_user[]" value="warp" checked><label class="btn btn-secondary" for="autorun_warp">순간이동</label>
<input type="checkbox" id="autorun_recruit" class="autorun_user_chk btn-check" data-key="recruit" name="autorun_user[]" value="recruit" checked><label class="btn btn-secondary" for="autorun_recruit">징병</label>
<input type="checkbox" id="autorun_recruit_high" class="autorun_user_chk btn-check" data-key="recruit_high" name="autorun_user[]" value="recruit_high" checked><label class="btn btn-secondary" for="autorun_recruit_high">모병</label>
<input type="checkbox" id="autorun_train" class="autorun_user_chk btn-check" data-key="train" name="autorun_user[]" value="train" checked><label class="btn btn-secondary" for="autorun_train">훈사</label>
<input type="checkbox" id="autorun_battle" class="autorun_user_chk btn-check" data-key="battle" name="autorun_user[]" value="battle" checked><label class="btn btn-secondary" for="autorun_battle">출병</label>
<input type="checkbox" id="autorun_chief" class="autorun_user_chk btn-check" data-key="chief" name="autorun_user[]" value="chief" checked><label class="btn btn-secondary" for="autorun_chief">기본 사령턴</label>
</div>
</div>
</div>
@@ -162,7 +164,7 @@ if ($session->userGrade < 5 && !$allowReset) {
<option value="480">8시간</option>
<option value="600">10시간</option>
<option value="720">12시간</option>
<option value="1440">24시간</option>
<option value="1440" selected>24시간</option>
<option value="2160">36시간</option>
<option value="2880">48시간</option>
<option value="3600">60시간</option>
+5 -3
View File
@@ -1,6 +1,8 @@
<?php
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
@@ -100,7 +102,7 @@ if(in_array($stateOpt, ['try_destroy_src', 'try_destroy_dest'])){
'reason'=>'파기'
];
}
$msgText = "외교 서신 #{$letterNo} 파기했습니다.";
$msgText = "외교 서신(#{$letterNo})을 파기했습니다.";
$lastState = 'cancelled';
}
else{
@@ -114,12 +116,12 @@ else{
'aux'=>Json::encode($aux)
], 'no=%i', $letterNo);
$msgText = "외교 서신 #{$letterNo} 파기 요청합니다.";
$msgText = "외교 서신(#{$letterNo})을 파기 요청합니다.";
$lastState = 'activated';
}
$msg = new Message(
Message::MSGTYPE_DIPLOMACY,
MessageType::diplomacy,
$src,
$dest,
$msgText,
+6 -4
View File
@@ -1,6 +1,8 @@
<?php
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
@@ -85,7 +87,7 @@ if($isAgree){
], 'no=%i', $prevLetterNo);
$prevLetterNo = $db->queryFirstField('SELECT prev_no FROM ng_diplomacy WHERE state != \'cancelled\' AND no = %i', $prevLetterNo);
}
$msgText = "외교 서신 #{$letterNo} 승인되었습니다.";
$msgText = "외교 서신( #{$letterNo})이 승인되었습니다.";
}
else{
$aux['reason'] = [
@@ -97,14 +99,14 @@ else{
'state'=>'cancelled',
'aux'=>Json::encode($aux)
], 'no=%i', $letterNo);
$msgText = "외교 서신 #{$letterNo} 거부되었습니다.";
$msgText = "외교 서신(#{$letterNo})이 거부되었습니다.";
if($reason){
$msgText .= ' 이유 : '.$reason;
}
}
$msg = new Message(
Message::MSGTYPE_DIPLOMACY,
MessageType::diplomacy,
$src,
$dest,
$msgText,
@@ -115,7 +117,7 @@ $msg = new Message(
$msgID = $msg->send();
$msg = new Message(
Message::MSGTYPE_NATIONAL,
MessageType::national,
$src,
$dest,
$msgText,
+4 -2
View File
@@ -1,6 +1,8 @@
<?php
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
@@ -70,10 +72,10 @@ $db->update('ng_diplomacy', [
'state'=>'cancelled',
'aux'=>Json::encode($aux)
], 'no=%i', $letterNo);
$msgText = "외교 서신 #{$letterNo} 회수되었습니다.";
$msgText = "외교 서신(#{$letterNo})이 회수되었습니다.";
$msg = new Message(
Message::MSGTYPE_DIPLOMACY,
MessageType::diplomacy,
$src,
$dest,
$msgText,
+3 -1
View File
@@ -1,6 +1,8 @@
<?php
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
@@ -176,7 +178,7 @@ else{
$msg = new Message(
Message::MSGTYPE_DIPLOMACY,
MessageType::diplomacy,
$src,
$dest,
$msgText,
+1 -1
View File
@@ -109,7 +109,7 @@ $scenario = (int)$_POST['scenario'];
$fiction = (int)$_POST['fiction'];
$extend = (int)$_POST['extend'];
$npcmode = (int)$_POST['npcmode'];
$block_general_create = (bool)$_POST['block_general_create'];
$block_general_create = (int)$_POST['block_general_create'];
$show_img_level = (int)$_POST['show_img_level'];
$tournament_trig = !!(int)$_POST['tournament_trig'];
$join_mode = $_POST['join_mode'];
-19
View File
@@ -1,19 +0,0 @@
<?php
namespace sammo;
include('lib.php');
include('func.php');
$session = Session::requireGameLogin([])->setReadOnly();
if(!Session::getInstance()->generalID){
Json::die([
"nation"=>[]
]);
}
//NOTE: 모든 국가, 모든 장수에 대해서 같은 결과라면 캐싱 가능하지 않을까?
Json::die([
"nation"=>getMailboxList()
]);
-63
View File
@@ -1,63 +0,0 @@
<?php
namespace sammo;
include 'lib.php';
include 'func.php';
WebUtil::requireAJAX();
//{msgID: 1206, response: true}
$session = Session::requireGameLogin([])->setReadOnly();
$generalID = Session::getInstance()->generalID;
if (!$generalID) {
Json::die([
'result'=>false,
'reason'=>'로그인하지 않음'
]);
}
$jsonPost = Json::decode(Util::getPost('data', 'string', '{}'));
$msgID = Util::toInt($jsonPost['msgID']??null);
$msgResponse = $jsonPost['response']??null;
if ($msgID === null || !is_bool($msgResponse)) {
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 인자'
]);
}
$general = DB::db()->queryFirstRow('SELECT `no`, `name`, `nation`, `officer_level`, `npc`, `gold`, `rice`, `troop`, `aux` from `general` where `no` = %i', $generalID);
if(!$general){
Json::die([
'result'=>false,
'reason'=>'존재하지 않는 장수'
]);
}
$msg = Message::getMessageByID($msgID);
if($msg === null){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 메시지'
]);
}
$reason = 'success';
$gameStor = KVStorage::getStorage(DB::db(), 'game_env');
$gameStor->cacheAll();
if($msgResponse){
$result = $msg->agreeMessage($general['no'], $reason);
}
else{
$result = $msg->declineMessage($general['no'], $reason);
}
Json::die([
'result' => $result!==DiplomaticMessage::INVALID,
'reason' => $reason
]);
-74
View File
@@ -1,74 +0,0 @@
<?php
namespace sammo;
include('lib.php');
include('func.php');
WebUtil::requireAJAX();
$session = Session::requireGameLogin([]);
$userID = Session::getUserID();
$msgID = Util::getPost('msgID', 'int');
if($msgID === null){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 범위 입니다.'
]);
}
$lastMsgGet = Json::decode($session->lastMsgGet)??[];
$now = new \DateTime();
$delayTime = false;
if(count($lastMsgGet) >= 10){
try{
if($lastMsgGet[0] !== 'string'){
throw new \Exception('Why not string?');
}
$first = new \DateTime($lastMsgGet[0]);
$diff = $first->diff($now);
if($diff->days == 0 && $diff->h > 0 && $diff->i == 0 && $diff->s <= 5){
$delayTime = true;
}
array_shift($lastMsgGet);
}
catch(\Exception $e){
$lastMsgGet = [];
}
}
$lastMsgGet[] = $now;
$session->lastMsgGet = Json::encode($lastMsgGet);
if($delayTime){
sleep(1);
}
$session->setReadOnly();
list($generalID, $nationID, $generalName) = DB::db()->queryFirstList(
'select `no`, `nation`, `name` from `general` where owner = %i',
$userID
);
if($nationID === null){
Json::die([
'result'=>false,
'reason'=>'장수가 사망했습니다.'
]);
}
$reason = Message::deleteMsg($msgID, $generalID);
if($reason === null){
$result = [
'result'=>true,
'reason'=>'success'
];
}
else{
$result = [
'result'=>false,
'reason'=>$reason
];
}
Json::die($result);
-118
View File
@@ -1,118 +0,0 @@
<?php
namespace sammo;
include('lib.php');
include('func.php');
$session = Session::requireGameLogin([]);
$userID = Session::getUserID();
$reqTo = Util::getPost('to', 'int');
$reqType = Util::getPost('type', 'string');
if($reqTo === null){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 범위 입니다.'
]);
}
if($reqType === null || !in_array($reqType, ['private', 'public', 'national', 'diplomacy'])){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 타입입니다.'
]);
}
$lastMsgGet = Json::decode($session->lastMsgGet)??[];
$now = new \DateTime();
$delayTime = false;
if(count($lastMsgGet) >= 10){
try{
if($lastMsgGet[0] !== 'string'){
throw new \Exception('Why not string?');
}
$first = new \DateTime($lastMsgGet[0]);
$diff = $first->diff($now);
if($diff->days == 0 && $diff->h > 0 && $diff->i == 0 && $diff->s <= 1){
$delayTime = true;
}
array_shift($lastMsgGet);
}
catch(\Exception $e){
$lastMsgGet = [];
}
}
$lastMsgGet[] = $now;
$session->lastMsgGet = Json::encode($lastMsgGet);
if($delayTime){
sleep(1);
}
$session->setReadOnly();
$me = DB::db()->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission FROM general WHERE `owner`=%i', $userID);
if($me === null){
Json::die([
'result'=>false,
'reason'=>'장수가 사망했습니다.'
]);
}
[$generalID, $nationID, $generalName] = [$me['no'], $me['nation'], $me['name']];
$permission = checkSecretPermission($me, false);
$result = [
'private'=>[],
'public'=>[],
'national'=>[],
'diplomacy'=>[],
'result'=>true,
'keepRecent'=>true,
'sequence'=>0,
'nationID'=>$nationID,
'generalName'=>$generalName,
];
$result['result'] = true;
$nextSequence = $reqTo;
if($reqType == 'private'){
$result['private'] = array_map(function(Message $msg) use (&$nextSequence){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
return $msg->toArray();
}, Message::getMessagesFromMailBoxOld($generalID, Message::MSGTYPE_PRIVATE, $reqTo, 15));
}
else if($reqType == 'public'){
$result['public'] = array_map(function(Message $msg)use (&$nextSequence){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
return $msg->toArray();
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_PUBLIC, Message::MSGTYPE_PUBLIC, $reqTo, 15));
}
else if($reqType == 'national'){
$result['national'] = array_map(function(Message $msg)use (&$nextSequence){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
return $msg->toArray();
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_NATIONAL + $nationID, Message::MSGTYPE_NATIONAL, $reqTo, 15));
}
else{
$result['diplomacy'] = array_map(function(Message $msg)use (&$nextSequence, $permission){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
$values = $msg->toArray();
if($msg->dest->nationID != 0 && $permission < 3){
$values['text'] = '(외교 메시지입니다)';//TODO: 외교서신이라 읽을 수 없음을 보여줘야함
$values['option']['invalid'] = true;
}
return $values;
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_NATIONAL + $nationID, Message::MSGTYPE_DIPLOMACY, $reqTo, 15));
}
Json::die($result);
-120
View File
@@ -1,120 +0,0 @@
<?php
namespace sammo;
include('lib.php');
include('func.php');
$session = Session::requireGameLogin([]);
$userID = Session::getUserID();
$reqSequence = Util::getPost('sequence', 'int', -1);
$lastMsgGet = Json::decode($session->lastMsgGet)??[];
$now = new \DateTime();
$delayTime = false;
if(count($lastMsgGet) >= 10){
try{
if(!is_string($lastMsgGet[0])){
throw new \Exception('Why not string?');
}
$first = new \DateTime($lastMsgGet[0]);
$diff = $first->diff($now);
if($diff->days == 0 && $diff->h > 0 && $diff->i == 0 && $diff->s <= 1){
$delayTime = true;
}
array_shift($lastMsgGet);
}
catch(\Exception $e){
$lastMsgGet = [];
}
}
$lastMsgGet[] = TimeUtil::now();
$session->lastMsgGet = Json::encode($lastMsgGet);
if($delayTime){
usleep(200);
}
$session->setReadOnly();
$db = DB::db();
$me = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission FROM general WHERE `owner`=%i', $userID);
if($me === null){
Json::die([
'result'=>false,
'reason'=>'장수가 사망했습니다.'
]);
}
[$generalID, $nationID, $generalName] = [$me['no'], $me['nation'], $me['name']];
$permission = checkSecretPermission($me, false);
$result = [];
$result['result'] = true;
$result['keepRecent'] = false;
$nextSequence = $reqSequence;
$minSequence = $reqSequence;
$lastType = null;
$result['private'] = array_map(function(Message $msg) use (&$nextSequence, &$minSequence, &$lastType){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
if($msg->id <= $minSequence){
$minSequence = $msg->id;
$lastType = 'private';
}
return $msg->toArray();
}, Message::getMessagesFromMailBox($generalID, Message::MSGTYPE_PRIVATE, 15, $reqSequence));
$result['public'] = array_map(function(Message $msg)use (&$nextSequence, &$minSequence, &$lastType){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
if($msg->id <= $minSequence){
$minSequence = $msg->id;
$lastType = 'public';
}
return $msg->toArray();
}, Message::getMessagesFromMailBox(Message::MAILBOX_PUBLIC, Message::MSGTYPE_PUBLIC, 15, $reqSequence));
$result['national'] = array_map(function(Message $msg)use (&$nextSequence, &$minSequence, &$lastType){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
if($msg->id <= $minSequence){
$minSequence = $msg->id;
$lastType = 'national';
}
return $msg->toArray();
}, Message::getMessagesFromMailBox(Message::MAILBOX_NATIONAL + $nationID, Message::MSGTYPE_NATIONAL, 15, $reqSequence));
$result['diplomacy']= array_map(function(Message $msg)use (&$nextSequence, &$minSequence, &$lastType, $permission){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
if($msg->id <= $minSequence){
$minSequence = $msg->id;
$lastType = 'diplomacy';
}
$values = $msg->toArray();
if($msg->dest->nationID != 0 && $permission < 3){
$values['text'] = '(외교 메시지입니다)';//TODO: 외교서신이라 읽을 수 없음을 보여줘야함
$values['option']['invalid'] = true;
}
return $values;
}, Message::getMessagesFromMailBox(Message::MAILBOX_NATIONAL + $nationID, Message::MSGTYPE_DIPLOMACY, 15, $reqSequence));
if($lastType !== null){
array_pop($result[$lastType]);
$result['keepRecent'] = true;
}
else if($reqSequence <= 0){
$result['keepRecent'] = true;
}
$result['sequence'] = $nextSequence;
$result['nationID'] = $nationID;
$result['generalName'] = $generalName;
Json::die($result);
-206
View File
@@ -1,206 +0,0 @@
<?php
namespace sammo;
include 'lib.php';
include 'func.php';
WebUtil::requireAJAX();
$post = Json::decode(Util::getPost('data', 'string', '{}'));
'@phan-var mixed[] $post';
$v = new Validator($post);
$v->rule('required', ['mailbox','text']);
$v->rule('integer', 'mailbox');
$v->rule('lengthMin', 'text', 1);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>$v->errorStr(),
'msgID'=>null
]);
}
$mailbox = (int)$post['mailbox'];
$text = trim(StringUtil::cutStringForWidth($post['text'], 199, ''));
$session = Session::requireGameLogin([
'msgID'=>null
]);
$userID = Session::getUserID();
//NOTE: 전송 메시지 시간 계산을 위해 Session을 쓰기 가능 상태로 열어둠.
increaseRefresh('서신전달', 1);
if(getBlockLevel() == 1 || getBlockLevel() == 3) {
Json::die([
'result' => false,
'reason' => '차단되었습니다.',
'msgID'=>null
]);
}
/**
* 메시지 전송 코드.
*
* TODO: 장기적으로 ajax는 한곳에 모을 필요가 있을 듯.
*/
$now = new \DateTime();
$unlimited = new \DateTime('9999-12-31');
$db = DB::db();
$me = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission,belong FROM general WHERE `owner`=%i', $userID);
if(!$me){
$session->logoutGame();
Json::die([
'result' => false,
'reason' => '로그인되지 않았습니다.',
'msgID' => null
]);
}
$con = checkLimit($me['con']);
if($con >= 2) {
Json::die([
'result' => false,
'reason' => '접속 제한입니다.',
'msgID' => null
]);
}
$me['icon'] = GetImageURL($me['imgsvr'], $me['picture']);
$permission = checkSecretPermission($me);
$srcNation = getNationStaticInfo($me['nation']);
$src = new MessageTarget($me['no'], $me['name'], $srcNation['nation'], $srcNation['name'], $srcNation['color'], $me['icon']);
// 전체 메세지
if($mailbox == Message::MAILBOX_PUBLIC) {
$msg = new Message(
Message::MSGTYPE_PUBLIC,
$src,
$src,
$text,
$now,
$unlimited,
[]
);
$msgID = $msg->send();
Json::die([
'result' => true,
'reason' => 'SUCCESS',
'msgID' => $msgID
]);
}
// 국가 메세지
if($mailbox >= Message::MAILBOX_NATIONAL) {
if($permission < 4){
$destNationID = $me['nation'];
}
else{
$destNationID = $mailbox - Message::MAILBOX_NATIONAL;
}
if($destNationID == $me['nation']){
$msgType = Message::MSGTYPE_NATIONAL;
}
else{
$msgType = Message::MSGTYPE_DIPLOMACY;
}
$destNation = getNationStaticInfo($destNationID);
$dest = new MessageTarget(0, '', $destNation['nation'], $destNation['name'], $destNation['color']);
$msg = new Message(
$msgType,
$src,
$dest,
$text,
$now,
$unlimited,
[]
);
$msgID = $msg->send();
Json::die([
'result' => true,
'reason' => 'SUCCESS',
'msgID' => $msgID
]);
}
// 개인 메세지
if($mailbox > 0) {
$lastMsg = new \DateTime($session->lastMsg??'0000-00-00');
$msg_interval = $now->getTimestamp() - $lastMsg->getTimestamp();
//NOTE: 여기서 유저 레벨을 구별할 코드가 필요할까?
if($msg_interval < 2){
Json::die([
'result' => false,
'reason' => '개인메세지는 2초당 1건만 보낼 수 있습니다!',
'msgID' => null
]);
}
$session->lastMsg = $now->format('Y-m-d H:i:s');
$destUser = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,permission,penalty FROM general WHERE `no`=%i',$mailbox);
if(!$destUser){
Json::die([
'result' => false,
'reason' => '존재하지 않는 유저입니다.',
'msgID' => null
]);
}
$destPermission = checkSecretPermission($destUser, false);
if($permission == 4 && $destPermission == 4 && $destUser['nation'] != $me['nation']){
Json::die([
'result' => false,
'reason' => '외교권자끼리는 메시지를 보낼 수 없습니다.',
'msgID' => null
]);
}
$destNation = getNationStaticInfo($destUser['nation']);
$dest = new MessageTarget(
$destUser['no'],
$destUser['name'],
$destNation['nation'],
$destNation['name'],
$destNation['color'],
GetImageURL($destUser['imgsvr'], $destUser['picture'])
);
$msg = new Message(
Message::MSGTYPE_PRIVATE,
$src,
$dest,
$text,
$now,
$unlimited,
[]
);
$msgID = $msg->send();
Json::die([
'result' => true,
'reason' => 'SUCCESS',
'msgID' => $msgID
]);
}
Json::die([
'result' => false,
'reason' => '알 수 없는 에러',
'msgID' => null
]);
+5 -3
View File
@@ -1,6 +1,8 @@
<?php
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
@@ -226,8 +228,8 @@ function do추방(General $general, int $myOfficerLevel):?string{
}
else{
$betrayCnt = $general->getVar('betray');
$general->addExperience(-$general->getVar('experience')*0.1*$betrayCnt);
$general->addDedication(-$general->getVar('dedication')*0.1*$betrayCnt);
$general->addExperience(-$general->getVar('experience')*0.15*$betrayCnt);
$general->addDedication(-$general->getVar('dedication')*0.15*$betrayCnt);
$general->increaseVarWithLimit('betray', 1, null, GameConst::$maxBetrayCnt);
}
@@ -268,7 +270,7 @@ function do추방(General $general, int $myOfficerLevel):?string{
GetImageURL($general->getVar('imgsvr'), $general->getVar('picture'))
);
$msg = new Message(
Message::MSGTYPE_PUBLIC,
MessageType::public,
$src,
$src,
$str,
+2 -2
View File
@@ -56,7 +56,7 @@ if(file_exists(__DIR__.'/.htaccess')){
'scenarioName'=>$options['scenarioName'],
'turnterm'=>$options['turnterm'],
'fictionMode'=>($options['fiction']?'가상':'사실'),
'block_general_create'=>(!!$options['block_general_create']),
'block_general_create'=>Util::toInt($options['block_general_create']),
'npcMode'=>([0=>'불가',1=>'가능',2=>'선택 생성'][$options['npcmode']]),
'openDatetime'=>$reserved['date'],
'starttime'=>$options['starttime'],
@@ -90,7 +90,7 @@ $admin['scenario'] = $admin['scenario_text'];
$admin['userCnt'] = $genCnt;
$admin['npcCnt'] = $npcCnt;
$admin['nationCnt'] = $nationCnt;
$admin['block_general_create'] = !!$admin['block_general_create'];
$admin['block_general_create'] = $admin['block_general_create'];
$admin['npcMode'] = [0=>'불가',1=>'가능',2=>'선택 생성'][$admin['npcMode']];
$admin['fictionMode'] = $admin['fiction']?'가상':'사실';
+1 -1
View File
@@ -44,7 +44,7 @@ if($defence_train !== $me->getVar('defence_train')){
$me->increaseVar('myset', -1);
$me->setVar('defence_train', $defence_train);
$me->increaseVarWithLimit('train', -3, 20);
$me->increaseVarWithLimit('atmos', -3, 20);
$me->increaseVarWithLimit('atmos', -6, 20);
}
else{
$me->increaseVar('myset', -1);
+1 -1
View File
@@ -82,7 +82,7 @@ function applyNationPolicy($policy, $nationID, $generalName): ?string
return "{$troopID}는 국가의 부대가 아닙니다.";
}
if ($troopCache[$troopID] != 'Neutral') {
return "부대({$troopID}는 하나의 역할만 지정할 수 있습니다.";
return "부대({$troopID})는 하나의 역할만 지정할 수 있습니다.";
}
if (!is_array($troopTarget) || count($troopTarget) != 2) {
return "{$troopID}의 입력양식이 올바르지 않습니다.";
+53 -6
View File
@@ -84,6 +84,7 @@ $rawDefenderList = $query['defenderGenerals'];
$rawDefenderCity = $query['defenderCity'];
$rawDefenderNation = $query['defenderNation'];
$warSeed = $query['seed'] ?? '';
$generalCheck = [
'required'=>[
@@ -132,6 +133,19 @@ $generalCheck = [
['weapon', array_merge(array_keys(GameConst::$allItems['weapon']), ['None'])],
['book', array_merge(array_keys(GameConst::$allItems['book']), ['None'])],
['item', array_merge(array_keys(GameConst::$allItems['item']), ['None'])],
],
'array'=>['inheritBuff'],
];
$inheritBuffCheck = [
'between'=>[
[TriggerInheritBuff::WAR_AVOID_RATIO, [0, 5]],
[TriggerInheritBuff::WAR_CRITICAL_RATIO, [0, 5]],
[TriggerInheritBuff::WAR_MAGIC_TRIAL_PROB, [0, 5]],
[TriggerInheritBuff::OPPOSE_WAR_AVOID_RATIO, [0, 5]],
[TriggerInheritBuff::OPPOSE_WAR_CRITICAL_RATIO, [0, 5]],
[TriggerInheritBuff::OPPOSE_WAR_MAGIC_TRIAL_PROB, [0, 5]],
]
];
@@ -143,6 +157,19 @@ if(!$v->validate()){
'reason'=>'[출병자]'.$v->errorStr()
]);
}
$rawAttacker['aux'] = [];
if(key_exists('inheritBuff', $rawAttacker)){
$v = new Validator($rawAttacker['inheritBuff']);
$v->rules($inheritBuffCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[출병자]'.$v->errorStr()
]);
}
$rawAttacker['aux']['inheritBuff'] = $rawAttacker['inheritBuff'];
}
$rawAttacker['aux'] = Json::encode($rawAttacker['aux']);
$rawAttacker['owner'] = 0;
$defenderList = [];
@@ -156,6 +183,20 @@ foreach($rawDefenderList as $idx=>$rawDefenderGeneral){
'reason'=>"[수비자{$idx}]".$v->errorStr()
]);
}
$rawDefenderGeneral['aux'] = [];
if(key_exists('inheritBuff', $rawDefenderGeneral)){
$v = new Validator($rawDefenderGeneral['inheritBuff']);
$v->rules($inheritBuffCheck);
if(!$v->validate()){
$idx+=1;
Json::die([
'result'=>false,
'reason'=>"[수비자{$idx}]".$v->errorStr()
]);
}
$rawDefenderGeneral['aux']['inheritBuff'] = $rawDefenderGeneral['inheritBuff'];
}
$rawDefenderGeneral['aux'] = Json::encode($rawDefenderGeneral['aux']);
$rawDefenderGeneral['owner'] = 0;
$defenderList[] = new General($rawDefenderGeneral, extractRankVar($rawDefenderGeneral), $rawDefenderCity, $rawAttackerNation, $year, $month, true);
@@ -281,7 +322,6 @@ unset($defenderList);
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$startYear = $gameStor->startyear;
$cityRate = Util::round(($year - $startYear) / 1.5) + 60;
function extractRankVar(array $rawVal):Map{
$rankVars = new Map;
@@ -298,10 +338,13 @@ function extractRankVar(array $rawVal):Map{
function simulateBattle(
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
$startYear, $year, $month, $cityRate
$startYear, $year, $month, $warSeed
){
$warSeed = bin2hex(random_bytes(16));
if(!$warSeed){
$warSeed = bin2hex(random_bytes(16));
}
$warRng = new RandUtil(new LiteHashDRBG($warSeed));
$attacker = new WarUnitGeneral(
@@ -310,7 +353,7 @@ function simulateBattle(
$rawAttackerNation,
true
);
$city = new WarUnitCity($warRng, $rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate);
$city = new WarUnitCity($warRng, $rawDefenderCity, $rawDefenderNation, $year, $month, $startYear);
$iterDefender = new \ArrayIterator($rawDefenderList);
$iterDefender->rewind();
@@ -367,7 +410,7 @@ function simulateBattle(
$rice = $city->getKilled() / 100 * 0.8;
$rice *= $city->getCrewType()->rice;
$rice *= getTechCost($rawDefenderNation['tech']);
$rice *= $cityRate / 100 - 0.2;
$rice *= $city->getCityTrainAtmos() / 100 - 0.2;
Util::setRound($rice);
$defenderRice += $rice;
@@ -401,12 +444,16 @@ $avgWar = 0;
$attackerActivatedSkills = [];
$defendersActivatedSkills = [];
if($warSeed){
$repeatCnt = 1;
}
foreach(Util::range($repeatCnt) as $repeatIdx){
/** @var WarUnit $attacker */
[$attacker, $city, $battleResult, $conquerCity, $attackerRice, $defenderRice] = simulateBattle(
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
$startYear, $year, $month, $cityRate
$startYear, $year, $month, $warSeed
);
$lastWarLog = Util::mapWithKey(function($key, $values){
return ConvertLog(join('<br>', $values));
-146
View File
@@ -1,146 +0,0 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
// $btn, $name, $troop
$action = Util::getPost('action');
$name = Util::getPost('name');
$gen = Util::getPost('gen', 'int');
$troop = Util::getPost('troop', 'int');
//로그인 검사
$session = Session::requireGameLogin([])->setReadOnly();
$userID = $session::getUserID();
increaseRefresh("부대명령", 0);
$db = DB::db();
$me = $db->queryFirstRow('SELECT `no`, name, nation, troop FROM general WHERE `owner`=%i', $userID);
$generalID = $me['no'];
$nationID = $me['nation'];
if($action == '부대창설'){
$name = StringUtil::neutralize($name);
if(!$name){
Json::die([
'result'=>false,
'reason'=>'부대 이름이 없습니다.'
]);
}
if($me['troop'] != 0){
Json::die([
'result'=>false,
'reason'=>'이미 부대에 가입해있습니다.'
]);
}
$db->insert('troop',[
'troop_leader'=>$generalID,
'name'=>$name,
'nation'=>$nationID,
]);
$db->update('general', [
'troop'=>$generalID,
], 'no=%i',$generalID);
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
if($action == '부대추방'){
if (!$gen){
Json::die([
'result'=>false,
'reason'=>'장수를 지정해야 합니다.'
]);
}
$db->update('general', [
'troop'=>0
], 'no=%i AND troop = %i', $gen, $generalID);
if($db->affectedRows() == 0){
Json::die([
'result'=>false,
'reason'=>'부대장이 아니거나, 장수를 잘못 지정했습니다.'
]);
}
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
if ($action == '부대가입') {
if(!$troop){
Json::die([
'result'=>false,
'reason'=>'부대를 지정해야 합니다.'
]);
}
if($me['troop'] === $generalID){
Json::die([
'result'=>false,
'reason'=>'부대장입니다.'
]);
}
$troopExists = $db->queryFirstField('SELECT `troop_leader` FROM `troop` WHERE `troop_leader` = %i AND `nation` = %i', $troop, $nationID);
if (!$troopExists) {
Json::die([
'result'=>false,
'reason'=>'올바른 부대장이 아닙니다.'
]);
}
$db->update('general', [
'troop'=>$troop
], 'no=%i', $generalID);
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
if($action == "부대탈퇴") {
if($me['troop'] == 0){
Json::die([
'result'=>false,
'reason'=>'부대에 속해있지 않습니다.'
]);
}
//부대장일 경우
if($me['troop'] === $generalID){
$db->update('general', [
'troop'=>0
], 'troop=%i',$generalID);
$db->delete('troop', 'troop_leader=%i', $generalID);
}
else{
$db->update('general', [
'troop'=>0
], 'no=%i', $generalID);
}
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 명령입니다.'
]);
+2 -2
View File
@@ -63,8 +63,8 @@ function prepareDir(string $dirPath, bool $forceCreate=true):bool{
if(!unlink($dirPath)){
return false;
}
return mkdir($dirPath);
return mkdir($dirPath, 0775);
}
return mkdir($dirPath, 0777, true);
return mkdir($dirPath, 0775, true);
}
+5 -6
View File
@@ -29,11 +29,11 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
}
$gameStor = KVStorage::getStorage($db, 'game_env');
[$startYear, $year, $month, $cityRate, $joinMode] = $gameStor->getValuesAsArray(['startyear', 'year', 'month', 'city_rate', 'join_mode']);
[$startYear, $year, $month, $joinMode] = $gameStor->getValuesAsArray(['startyear', 'year', 'month', 'join_mode']);
$attacker = new WarUnitGeneral($rng, $attackerGeneral,$rawAttackerNation, true);
$city = new WarUnitCity($rng, $rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate);
$city = new WarUnitCity($rng, $rawDefenderCity, $rawDefenderNation, $year, $month, $startYear);
$defenderIDList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND city=%i AND nation!=0 and crew > 0 and rice>(crew/100) and train>=defence_train and atmos>=defence_train', $city->getVar('nation'), $city->getVar('city'));
$defenderList = General::createGeneralObjListFromDB($defenderIDList, null, 2);
@@ -90,7 +90,7 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
$rice = $city->getKilled() / 100 * 0.8;
$rice *= $city->getCrewType()->rice;
$rice *= getTechCost($rawDefenderNation['tech']);
$rice *= $cityRate / 100 - 0.2;
$rice *= $city->getCityTrainAtmos() / 100 - 0.2;
Util::setRound($rice);
$updateDefenderNation['rice'] = max(0, $rawDefenderNation['rice'] - $rice);
@@ -113,8 +113,8 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
'dead' => $db->sqleval('dead + %i', $totalDead * 0.6)
], 'city=%i', $rawDefenderCity['city']);
$attackerIncTech = buildNationTypeClass($rawAttackerNation['type'])->onCalcDomestic('기술', 'score', $attacker->getDead() * 0.01);
$defenderIncTech = buildNationTypeClass($rawDefenderNation['type'])->onCalcDomestic('기술', 'score', $attacker->getKilled() * 0.01);
$attackerIncTech = buildNationTypeClass($rawAttackerNation['type'])->onCalcDomestic('기술', 'score', $attacker->getDead() * 0.012);
$defenderIncTech = buildNationTypeClass($rawDefenderNation['type'])->onCalcDomestic('기술', 'score', $attacker->getKilled() * 0.009);
$attackerGenCnt = $rawAttackerNation['gennum'];
$defenderGenCnt = $rawDefenderNation['gennum'];
@@ -175,7 +175,6 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
'startyear' => $startYear,
'year' => $year,
'month' => $month,
'city_rate' => $cityRate,
'join_mode' => $joinMode,
], $attacker->getGeneral(), $city->getRaw());
}
+1
View File
@@ -27,6 +27,7 @@ include "func.php";
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printCSS('css/map.css') ?>
<?= WebUtil::printDist('ts', ['common', 'recent_map'], true) ?>
<?= WebUtil::printDist('vue', [], true) ?>
<style>
html {
width: 700px;
+1 -1
View File
@@ -26,7 +26,7 @@ class Bet extends \sammo\BaseAPI
->rule('int', 'bettingID')
->rule('integerArray', 'bettingType')
->rule('int', 'amount')
->rule('min', 'amount', 1);
->rule('min', 'amount', 10);
if (!$v->validate()) {
return $v->errorStr();
+3 -3
View File
@@ -4,7 +4,7 @@ namespace sammo\API\General;
use sammo\DB;
use sammo\DummyGeneral;
use sammo\GameConst;
use sammo\Session;
use sammo\General;
use sammo\JosaUtil;
@@ -54,7 +54,7 @@ class DieOnPrestart extends \sammo\BaseAPI
}
//서버 가오픈시 할 수 있는 행동
$targetTime = addTurn($general['lastrefresh'], $gameStor->turnterm, 2);
$targetTime = addTurn($general['lastrefresh'], $gameStor->turnterm, GameConst::$minTurnDieOnPrestart);
if ($targetTime > TimeUtil::now()) {
$targetTimeShort = substr($targetTime, 0, 19);
return "아직 삭제할 수 없습니다. {$targetTimeShort} 부터 가능합니다.";
@@ -67,7 +67,7 @@ class DieOnPrestart extends \sammo\BaseAPI
$generalName = $generalObj->getName();
$josaYi = JosaUtil::pick($generalName, '이');
$generalObj->kill($db, true, "<Y>{$generalName}</>{$josaYi} 홀연히 모습을 <R>감추었습니다</>");
$generalObj->kill($db, true, "<Y>{$generalName}</>{$josaYi} 홀연히 모습을 <R>감추었습니다</>");
$session->logoutGame();
return null;
+78 -10
View File
@@ -2,7 +2,9 @@
namespace sammo\API\General;
use Ds\Set;
use sammo\ActionLogger;
use sammo\Auction;
use sammo\CityConst;
use sammo\DB;
use sammo\Enums\RankColumn;
@@ -84,6 +86,40 @@ class Join extends \sammo\BaseAPI
return static::REQ_LOGIN | static::REQ_READ_ONLY;
}
public function calcRestInheritPoint(int $userID): int
{
$db = DB::db();
if (Util::toInt(UniqueConst::$seasonIdx) < 1) {
//이벤트 시즌은 카운트하지 않음
return 0;
}
$gameID = UniqueConst::$serverID;
$alreadyJoined = $db->queryFirstField('SELECT count(*) FROM `storage` WHERE `namespace` = %s AND `key` LIKE %s', 'inheritance_result', "{$gameID}_{$userID}_%");
if ($alreadyJoined) {
//이미 받았음
return 0;
}
$targetBonusPointCnt = 0;
//정상적으로 끝난 깃수만 제공
$oldGames = $db->queryFirstColumn('SELECT server_id FROM ng_games WHERE `winner_nation` IS NOT NULL AND `season` >= 1 AND `server_id` != %s ORDER BY `date` DESC LIMIT 8', $gameID);
if(!$oldGames){
return 0;
}
//이전에 장수를 생성한 적이 있는지
$oldGamesCnt = new Set($db->queryFirstColumn('SELECT `server_id` FROM ng_old_generals WHERE server_id IN %ls AND `owner` = %i GROUP BY `server_id`', $oldGames, $userID));
foreach ($oldGames as $oldGameID) {
if($oldGamesCnt->contains($oldGameID)) {
break;
}
$targetBonusPointCnt += 1;
}
return $targetBonusPointCnt;
}
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$userID = $session->userID;
@@ -105,7 +141,7 @@ class Join extends \sammo\BaseAPI
$inheritCity = $this->args['inheritCity'] ?? null;
$inheritBonusStat = $this->args['inheritBonusStat'] ?? null;
if($inheritTurntime !== null && $inheritCity !== null){
if ($inheritTurntime !== null && $inheritCity !== null) {
return '턴과 도시를 동시에 지정할 수 없습니다.';
}
@@ -119,9 +155,16 @@ class Join extends \sammo\BaseAPI
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheValues(['year', 'month', 'maxgeneral', 'scenario', 'show_img_level', 'turnterm', 'turntime', 'genius', 'npcmode']);
$gameStor->cacheValues(['year', 'month', 'maxgeneral', 'scenario', 'show_img_level', 'block_general_create', 'turnterm', 'turntime', 'genius', 'npcmode']);
########## 동일 정보 존재여부 확인. ##########
$block_general_create = $gameStor->getValue('block_general_create');
if($block_general_create & 1){
return '장수 직접 생성이 불가능한 모드입니다.';
}
$blockCustomGeneralName = $gameStor->getValue('block_general_create') & 2;
$gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2');
$oldGeneral = $db->queryFirstField('SELECT `no` FROM general WHERE `owner`=%i', $userID);
$oldName = $db->queryFirstField('SELECT `no` FROM general WHERE `name`=%s', $name);
@@ -305,7 +348,7 @@ class Join extends \sammo\BaseAPI
if ($inheritTurntime !== null) {
$inheritTurntime = $inheritTurntime % ($admin['turnterm'] * 60);
$userLogger->push(sprintf("턴 시간 %02d:%02d 로 지정", intdiv($inheritTurntime, 60), $inheritTurntime%60), "inheritPoint");
$userLogger->push(sprintf("턴 시간 %02d:%02d 로 지정", intdiv($inheritTurntime, 60), $inheritTurntime % 60), "inheritPoint");
$inheritTurntime += $rng->nextRangeInt(0, 999999) / 1000000;
$turntime = new \DateTimeImmutable(cutTurn($admin['turntime'], $admin['turnterm']));
@@ -337,6 +380,15 @@ class Join extends \sammo\BaseAPI
//상성 랜덤
$affinity = $rng->nextRangeInt(1, 150);
$betray = 0;
if ($relYear >= 4) {
$betray += 2;
}
if($blockCustomGeneralName){
$name = bin2hex(random_bytes(5));
}
########## 회원정보 테이블에 입력값을 등록한다. ##########
$db->insert('general', [
'owner' => $userID,
@@ -365,6 +417,7 @@ class Join extends \sammo\BaseAPI
'lastrefresh' => $now,
'crewtype' => GameUnitConst::DEFAULT_CREWTYPE,
'makelimit' => 0,
'betray' => $betray,
'age' => $age,
'startage' => $age,
'personal' => $character,
@@ -374,6 +427,15 @@ class Join extends \sammo\BaseAPI
'special2' => $special2
]);
$generalID = $db->insertId();
if($blockCustomGeneralName){
//XXX: 클래스가 이게 맞나?
$name = Auction::genObfuscatedName($generalID);
$db->update('general', [
'name' => $name
], 'no=%i', $generalID);
}
$turnRows = [];
foreach (Util::range(GameConst::$maxTurn) as $turnIdx) {
$turnRows[] = [
@@ -402,19 +464,25 @@ class Join extends \sammo\BaseAPI
if ($inheritRequiredPoint > 0) {
$userLogger->push("장수 생성으로 포인트 {$inheritRequiredPoint} 소모", "inheritPoint");
$inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$userID}");
$inheritStor->setValue('previous', [$inheritTotalPoint - $inheritRequiredPoint, null]);
$inheritTotalPoint -= $inheritRequiredPoint;
$inheritStor->setValue('previous', [$inheritTotalPoint, null]);
$userLogger->flush();
$db->update('rank_data', [
'value'=>$db->sqleval('value + %i', $inheritRequiredPoint)
'value' => $db->sqleval('value + %i', $inheritRequiredPoint)
], 'general_id = %i AND type = %s', $generalID, RankColumn::inherit_point_spent_dynamic->value);
}
$me = [
'no' => $generalID
];
$log = [];
$mylog = [];
$restInheritPoint = $this->calcRestInheritPoint($userID) * 500;
if($restInheritPoint > 0){
$userLogger->push("신규/복귀 생성으로 포인트 {$restInheritPoint} 지급", "inheritPoint");
$inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$userID}");
$inheritTotalPoint += $restInheritPoint;
$inheritStor->setValue('previous', [$inheritTotalPoint, null]);
$userLogger->flush();
}
$logger = new ActionLogger($generalID, 0, $gameStor->year, $gameStor->month);
+16 -1
View File
@@ -3,8 +3,10 @@
namespace sammo\API\Global;
use sammo\Session;
use sammo\DB;
use DateTimeInterface;
use sammo\TurnExecutionHelper;
use sammo\UniqueConst;
class ExecuteEngine extends \sammo\BaseAPI
{
@@ -20,10 +22,23 @@ class ExecuteEngine extends \sammo\BaseAPI
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$updated = TurnExecutionHelper::executeAllCommand();
$reqServerID = $this->args['serverID'] ?? null;
if($reqServerID && $reqServerID !== UniqueConst::$serverID){
return [
'result' => false,
'reason' => '서버 아이디가 다릅니다',
'reqRefresh' => true,
];
}
$updated = false;
$locked = false;
$lastExecuted = TurnExecutionHelper::executeAllCommand($updated, $locked);
return [
'result' => true,
'updated' => $updated,
'locked' => $locked,
'lastExecuted' => $lastExecuted,
];
}
}
+128
View File
@@ -0,0 +1,128 @@
<?php
namespace sammo\API\Global;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\Util;
use sammo\Validator;
class GetRecentRecord extends \sammo\BaseAPI
{
const ROW_LIMIT = 15;
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('int', 'lastGeneralRecordID')
->rule('int', 'lastWorldHistoryID');
if (!$v->validate()) {
return $v->errorStr();
}
$this->args['lastGeneralRecordID'] = (int)($this->args['lastGeneralRecordID']??0);
$this->args['lastWorldHistoryID'] = (int)($this->args['lastWorldHistoryID']??0);
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
private function getGlobalRecord(int $lastRecordID): array
{
$db = DB::db();
$globalRecord = $db->queryAllLists(
'SELECT id, `text` FROM general_record WHERE `general_id` = 0 AND log_type = %s AND id >= %i ORDER BY `id` DESC LIMIT %i',
'history',
$lastRecordID,
static::ROW_LIMIT + 1,
);
return $globalRecord;
}
private function getGeneralRecord(int $generalID, int $lastRecordID): array
{
$db = DB::db();
$generalRecord = $db->queryAllLists(
'SELECT id, `text` FROM general_record WHERE `general_id` = %i AND log_type = %s AND id >= %i ORDER BY `id` DESC LIMIT %i',
$generalID,
'action',
$lastRecordID,
static::ROW_LIMIT + 1,
);
return $generalRecord;
}
private function getHistory(int $lastHistoryID): array
{
$db = DB::db();
$history = $db->queryAllLists(
'SELECT id, `text` FROM world_history WHERE nation_id = 0 AND id >= %i ORDER BY `id` DESC LIMIT %i',
$lastHistoryID,
static::ROW_LIMIT + 1,
);
return $history;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$db = DB::db();
$lastHistoryID = $this->args['lastWorldHistoryID'];
$lastRecordID = $this->args['lastGeneralRecordID'];
$history = $this->getHistory($lastHistoryID);
$globalRecord = $this->getGlobalRecord($lastRecordID);
$generalRecord = $this->getGeneralRecord($session->generalID, $lastRecordID);
$flushHistory = true;
$flushGlobalRecord = true;
$flushGeneralRecord = true;
if($history){
if(Util::array_last($history)[0] == $lastHistoryID){
$flushHistory = false;
array_pop($history);
}
else if(count($history) > static::ROW_LIMIT){
array_pop($history);
}
}
if($globalRecord){
if(Util::array_last($globalRecord)[0] == $lastRecordID){
$flushGlobalRecord = false;
array_pop($globalRecord);
}
else if(count($globalRecord) > static::ROW_LIMIT){
array_pop($globalRecord);
}
}
if($generalRecord){
if(Util::array_last($generalRecord)[0] == $lastRecordID){
$flushGeneralRecord = false;
array_pop($generalRecord);
}
else if(count($generalRecord) > static::ROW_LIMIT){
array_pop($generalRecord);
}
}
return [
'result' => true,
'history' => $history,
'global' => $globalRecord,
'general' => $generalRecord,
'flushHistory' => $flushHistory?1:0,
'flushGlobal' => $flushGlobalRecord?1:0,
'flushGeneral' => $flushGeneralRecord?1:0,
];
}
}
@@ -0,0 +1,61 @@
<?php
namespace sammo\API\Message;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\DiplomaticMessage;
use sammo\KVStorage;
use sammo\Message;
use sammo\Validator;
class DecideMessageResponse extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('required', ['msgID', 'response']);
$v->rule('integer', 'msgID')
->rule('boolean', 'response');
if (!$v->validate()) {
return $v->errorStr();
}
$this->args['msgID'] = (int)($this->args['msgID'] ?? -1);
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$msgID = $this->args['msgID'];
$msgResponse = $this->args['response'];
$generalID = $session->generalID;
$msg = Message::getMessageByID($msgID);
if ($msg === null) {
return '존재하지 않는 메시지입니다.';
}
$reason = 'success';
$gameStor = KVStorage::getStorage(DB::db(), 'game_env');
$gameStor->cacheAll();
if ($msgResponse) {
$result = $msg->agreeMessage($generalID, $reason);
} else {
$result = $msg->declineMessage($generalID, $reason);
}
return [
'result' => $result !== DiplomaticMessage::INVALID,
'reason' => $reason
];
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
namespace sammo\API\Message;
use sammo\Session;
use DateTimeInterface;
use sammo\Message;
use sammo\Validator;
class DeleteMessage extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('required', ['msgID']);
$v->rule('integer', 'msgID');
if (!$v->validate()) {
return $v->errorStr();
}
$this->args['msgID'] = (int)($this->args['msgID'] ?? -1);
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$msgID = $this->args['msgID'];
$generalID = $session->generalID;
return Message::deleteMsg($msgID, $generalID);
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace sammo\API\Message;
use sammo\Session;
use DateTimeInterface;
use function sammo\getMailboxList;
class GetContactList extends \sammo\BaseAPI{
public function validateArgs(): ?string
{
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
if(!$session->generalID){
return [
"nation"=>[]
];
}
//NOTE: 모든 국가, 모든 장수에 대해서 같은 결과라면 캐싱 가능하지 않을까?
return [
"nation"=>getMailboxList()
];
}
}
+143
View File
@@ -0,0 +1,143 @@
<?php
namespace sammo\API\Message;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\Enums\MessageType;
use sammo\Json;
use sammo\Message;
use sammo\TimeUtil;
use sammo\Util;
use sammo\Validator;
use function sammo\checkSecretPermission;
class GetOldMessage extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('required', [
'to',
'type',
])->rule('integer', 'to')
->rule('in', 'type', ['private', 'public', 'national', 'diplomacy']);
if (!$v->validate()) {
return $v->errorStr();
}
$this->args['to'] = (int)($this->args['to'] ?? 0);
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN;
}
private function delayFrequentCall(Session $session): void
{
$lastMsgGet = Json::decode($session->lastMsgGet) ?? [];
$now = new \DateTimeImmutable();
$delayTime = false;
if (count($lastMsgGet) >= 10) {
try {
if (!is_string($lastMsgGet[0])) {
throw new \Exception('Why not string?');
}
$first = new \DateTimeImmutable($lastMsgGet[0]);
$diffSec = TimeUtil::DateIntervalToSeconds($first->diff($now));
if ($diffSec < 1) {
$delayTime = true;
}
array_shift($lastMsgGet);
} catch (\Exception $e) {
$lastMsgGet = [];
}
}
$lastMsgGet[] = TimeUtil::format($now, true);
$session->lastMsgGet = Json::encode($lastMsgGet);
if ($delayTime) {
usleep(200);
}
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$this->delayFrequentCall($session);
$session->setReadOnly();
$userID = $session->getUserID();
$db = DB::db();
$me = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission FROM general WHERE `owner`=%i', $userID);
if ($me === null) {
return '장수가 사망했습니다.';
}
[$generalID, $nationID, $generalName] = [$me['no'], $me['nation'], $me['name']];
$permission = checkSecretPermission($me, false);
$reqTo = $this->args['to'];
$result = [
MessageType::private->value => [],
MessageType::public->value => [],
MessageType::national->value => [],
MessageType::diplomacy->value => [],
'result' => true,
'keepRecent' => true,
'sequence' => 0,
'nationID' => $nationID,
'generalName' => $generalName,
];
$result['result'] = true;
$nextSequence = $reqTo;
$reqType = MessageType::tryFrom($this->args['type']);
if ($reqType === null) {
return '잘못된 요청입니다.';
}
if ($reqType === MessageType::private) {
$result[MessageType::private->value] = array_map(function (Message $msg) use (&$nextSequence) {
if ($msg->id > $nextSequence) {
$nextSequence = $msg->id;
}
return $msg->toArray();
}, Message::getMessagesFromMailBoxOld($generalID, MessageType::private, $reqTo, 15));
} else if ($reqType === MessageType::public) {
$result[MessageType::public->value] = array_map(function (Message $msg) use (&$nextSequence) {
if ($msg->id > $nextSequence) {
$nextSequence = $msg->id;
}
return $msg->toArray();
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_PUBLIC, MessageType::public, $reqTo, 15));
} else if ($reqType === MessageType::national) {
$result[MessageType::national->value] = array_map(function (Message $msg) use (&$nextSequence) {
if ($msg->id > $nextSequence) {
$nextSequence = $msg->id;
}
return $msg->toArray();
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_NATIONAL + $nationID, MessageType::national, $reqTo, 15));
} else {
$result[MessageType::diplomacy->value] = array_map(function (Message $msg) use (&$nextSequence, $permission) {
if ($msg->id > $nextSequence) {
$nextSequence = $msg->id;
}
$values = $msg->toArray();
if ($msg->dest->nationID != 0 && $permission < 3) {
$values['text'] = '(외교 메시지입니다)'; //TODO: 외교서신이라 읽을 수 없음을 보여줘야함
$values['option']['invalid'] = true;
}
return $values;
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_NATIONAL + $nationID, MessageType::diplomacy, $reqTo, 15));
}
return $result;
}
}
+152
View File
@@ -0,0 +1,152 @@
<?php
namespace sammo\API\Message;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\Enums\MessageType;
use sammo\Json;
use sammo\Message;
use sammo\TimeUtil;
use sammo\Util;
use sammo\Validator;
use function sammo\checkSecretPermission;
class GetRecentMessage extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('integer', 'sequence');
if (!$v->validate()) {
return $v->errorStr();
}
$this->args['sequence'] = (int)($this->args['sequence'] ?? -1);
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN;
}
private function delayFrequentCall(Session $session): void
{
$lastMsgGet = Json::decode($session->lastMsgGet) ?? [];
$now = new \DateTimeImmutable();
$delayTime = false;
if (count($lastMsgGet) >= 10) {
try {
if (!is_string($lastMsgGet[0])) {
throw new \Exception('Why not string?');
}
$first = new \DateTimeImmutable($lastMsgGet[0]);
$diffSec = TimeUtil::DateIntervalToSeconds($first->diff($now));
if ($diffSec < 1) {
$delayTime = true;
}
array_shift($lastMsgGet);
} catch (\Exception $e) {
$lastMsgGet = [];
}
}
$lastMsgGet[] = TimeUtil::format($now, true);
$session->lastMsgGet = Json::encode($lastMsgGet);
if ($delayTime) {
usleep(200);
}
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$this->delayFrequentCall($session);
$session->setReadOnly();
$userID = $session->getUserID();
$db = DB::db();
$me = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission FROM general WHERE `owner`=%i', $userID);
if ($me === null) {
return '장수가 사망했습니다.';
}
[$generalID, $nationID, $generalName] = [$me['no'], $me['nation'], $me['name']];
$permission = checkSecretPermission($me, false);
$reqSequence = $this->args['sequence'];
$result = [];
$result['result'] = true;
$result['keepRecent'] = false;
$nextSequence = $reqSequence;
$minSequence = $reqSequence;
$lastType = null;
$result['private'] = array_map(function (Message $msg) use (&$nextSequence, &$minSequence, &$lastType) {
if ($msg->id > $nextSequence) {
$nextSequence = $msg->id;
}
if ($msg->id <= $minSequence) {
$minSequence = $msg->id;
$lastType = 'private';
}
return $msg->toArray();
}, Message::getMessagesFromMailBox($generalID, MessageType::private, 15, $reqSequence));
$result['public'] = array_map(function (Message $msg) use (&$nextSequence, &$minSequence, &$lastType) {
if ($msg->id > $nextSequence) {
$nextSequence = $msg->id;
}
if ($msg->id <= $minSequence) {
$minSequence = $msg->id;
$lastType = 'public';
}
return $msg->toArray();
}, Message::getMessagesFromMailBox(Message::MAILBOX_PUBLIC, MessageType::public, 15, $reqSequence));
$result['national'] = array_map(function (Message $msg) use (&$nextSequence, &$minSequence, &$lastType) {
if ($msg->id > $nextSequence) {
$nextSequence = $msg->id;
}
if ($msg->id <= $minSequence) {
$minSequence = $msg->id;
$lastType = 'national';
}
return $msg->toArray();
}, Message::getMessagesFromMailBox(Message::MAILBOX_NATIONAL + $nationID, MessageType::national, 15, $reqSequence));
$result['diplomacy'] = array_map(function (Message $msg) use (&$nextSequence, &$minSequence, &$lastType, $permission) {
if ($msg->id > $nextSequence) {
$nextSequence = $msg->id;
}
if ($msg->id <= $minSequence) {
$minSequence = $msg->id;
$lastType = 'diplomacy';
}
$values = $msg->toArray();
if ($msg->dest->nationID != 0 && $permission < 3) {
$values['text'] = '(외교 메시지입니다)'; //TODO: 외교서신이라 읽을 수 없음을 보여줘야함
$values['option']['invalid'] = true;
}
return $values;
}, Message::getMessagesFromMailBox(Message::MAILBOX_NATIONAL + $nationID, MessageType::diplomacy, 15, $reqSequence));
if ($lastType !== null) {
array_pop($result[$lastType]);
$result['keepRecent'] = true;
} else if ($reqSequence <= 0) {
$result['keepRecent'] = true;
}
$result['sequence'] = $nextSequence;
$result['nationID'] = $nationID;
$result['generalName'] = $generalName;
return $result;
}
}
+240
View File
@@ -0,0 +1,240 @@
<?php
namespace sammo\API\Message;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\Enums\MessageType;
use sammo\Message;
use sammo\MessageTarget;
use sammo\Validator;
use function sammo\checkLimit;
use function sammo\checkSecretPermission;
use function sammo\getBlockLevel;
use function sammo\GetImageURL;
use function sammo\getNationStaticInfo;
use function sammo\increaseRefresh;
class SendMessage extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('required', ['mailbox', 'text']);
$v->rule('integer', 'mailbox');
$v->rule('lengthMin', 'text', 1);
if (!$v->validate()) {
return $v->errorStr();
}
$this->args['mailbox'] = (int)($this->args['mailbox'] ?? Message::MAILBOX_PUBLIC);
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN;
}
private function genPublicMessage(MessageTarget $src, string $text): Message
{
$now = new \DateTime();
$unlimited = new \DateTime('9999-12-31');
$msg = new Message(
MessageType::public,
$src,
$src,
$text,
$now,
$unlimited,
[]
);
return $msg;
}
private function genNationalMessage(MessageTarget $src, string $text): Message
{
$now = new \DateTime();
$unlimited = new \DateTime('9999-12-31');
$dest = new MessageTarget(0, '', $src->nationID, $src->nationName, $src->color);
$msg = new Message(
MessageType::national,
$src,
$dest,
$text,
$now,
$unlimited,
[]
);
return $msg;
}
private function genDiplomacyMessage(MessageTarget $src, int $destNationID, string $text): Message|string
{
$now = new \DateTime();
$unlimited = new \DateTime('9999-12-31');
$destNation = getNationStaticInfo($destNationID);
if ($destNation === null) {
return '존재하지 않는 국가입니다.';
}
$dest = new MessageTarget(0, '', $destNation['nation'], $destNation['name'], $destNation['color']);
$msg = new Message(
MessageType::diplomacy,
$src,
$dest,
$text,
$now,
$unlimited,
[]
);
return $msg;
}
private function genPrivateMessage(MessageTarget $src, int $destGeneralID, int $permission, string $text): Message|string
{
$now = new \DateTime();
$unlimited = new \DateTime('9999-12-31');
$db = DB::db();
$destUser = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,permission,penalty FROM general WHERE `no`=%i', $destGeneralID);
if (!$destUser) {
return '존재하지 않는 유저입니다.';
}
$destPermission = checkSecretPermission($destUser, false);
if ($permission == 4 && $destPermission == 4 && $destUser['nation'] != $src->nationID) {
return '외교권자끼리는 메시지를 보낼 수 없습니다.';
}
$destNation = getNationStaticInfo($destUser['nation']);
if ($destNation === null) {
$destNation = getNationStaticInfo(0);
}
$dest = new MessageTarget(
$destUser['no'],
$destUser['name'],
$destNation['nation'],
$destNation['name'],
$destNation['color'],
GetImageURL($destUser['imgsvr'], $destUser['picture'])
);
$msg = new Message(
MessageType::private,
$src,
$dest,
$text,
$now,
$unlimited,
[]
);
return $msg;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$userID = $session->userID;
$mailbox = $this->args['mailbox'];
$text = $this->args['text'];
increaseRefresh('서신전달', 1);
$blockLevel = getBlockLevel();
if ($blockLevel == 1 || $blockLevel == 3) {
return '차단되었습니다.';
}
$db = DB::db();
$me = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission,belong FROM general WHERE `owner`=%i', $userID);
if (!$me) {
$session->logoutGame();
return '장수가 없습니다.';
}
$con = checkLimit($me['con']);
if ($con >= 2) {
return '접속 제한입니다.';
}
$nationID = $me['nation'];
$iconPath = GetImageURL($me['imgsvr'], $me['picture']);
$srcNation = getNationStaticInfo($me['nation']);
if ($srcNation === null) {
return '존재하지 않는 국가입니다.';
}
$src = new MessageTarget($me['no'], $me['name'], $srcNation['nation'], $srcNation['name'], $srcNation['color'], $iconPath);
// 전체 메세지
if ($mailbox === Message::MAILBOX_PUBLIC) {
$msgID = $this->genPublicMessage($src, $text)->send();
return [
'msgID' => $msgID
];
}
$permission = checkSecretPermission($me);
if ($mailbox >= Message::MAILBOX_NATIONAL) {
if ($permission < 4) {
$destNationID = $nationID;
} else {
$destNationID = $mailbox - Message::MAILBOX_NATIONAL;
}
if ($destNationID === $nationID) {
$msgID = $this->genNationalMessage($src, $text)->send();
return [
'msgID' => $msgID
];
}
$msgObjOrError = $this->genDiplomacyMessage($src, $destNationID, $text);
if(is_string($msgObjOrError)) {
return $msgObjOrError;
}
$msgID = $msgObjOrError->send();
return [
'msgID' => $msgID
];
}
if ($mailbox > 0) {
$now = new \DateTime();
$lastMsg = new \DateTime($session->lastMsg ?? '0000-00-00');
$msg_interval = $now->getTimestamp() - $lastMsg->getTimestamp();
if ($msg_interval < 2) {
return '개인메세지는 2초당 1건만 보낼 수 있습니다!';
}
$session->lastMsg = $now->format('Y-m-d H:i:s');
$msgObjOrError = $this->genPrivateMessage($src, $mailbox, $permission, $text);
if(is_string($msgObjOrError)) {
return $msgObjOrError;
}
$msgID = $msgObjOrError->send();
return [
'msgID' => $msgID
];
}
return '알 수 없는 에러입니다.';
}
}
+1 -1
View File
@@ -81,7 +81,7 @@ class GetGeneralLog extends \sammo\BaseAPI
if (
$reqType === self::GENERAL_ACTION &&
$testGeneralNPCType < 2 &&
$generalID !== $me['generalID'] &&
$generalID !== $me['no'] &&
$permission < 2
) {
return '권한이 부족합니다. 유저 장수의 개인 기록은 수뇌만 열람 가능합니다.';
+8 -2
View File
@@ -6,6 +6,7 @@ use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\KVStorage;
use sammo\TimeUtil;
use sammo\Validator;
use sammo\WebUtil;
@@ -36,7 +37,7 @@ class SetNotice extends \sammo\BaseAPI
$msg = $this->args['msg'];
$userID = $session->userID;
$db = DB::db();
$me = $db->queryFirstRow('SELECT `no`,nation,`officer_level`,permission,penalty FROM general WHERE `owner`=%i', $userID);
$me = $db->queryFirstRow('SELECT `no`,`name`,nation,`officer_level`,permission,penalty FROM general WHERE `owner`=%i', $userID);
$permission = checkSecretPermission($me, false);
if($permission < 0){
@@ -49,7 +50,12 @@ class SetNotice extends \sammo\BaseAPI
$nationID = $me['nation'];
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$nationStor->notice = WebUtil::htmlPurify($msg);
$nationStor->nationNotice = [
'date'=>TimeUtil::now(),
'msg'=>WebUtil::htmlPurify($msg),
'author'=>$me['name'],
'authorID'=>$me['no'],
];
return [
'result' => true
+2 -2
View File
@@ -5,8 +5,8 @@ use \sammo\General;
class che_계략_향낭 extends \sammo\BaseItem{
protected $rawName = '항냥';
protected $name = '항냥(계략)';
protected $rawName = '향낭';
protected $name = '향낭(계략)';
protected $info = '[계략] 화계·탈취·파괴·선동 : 성공률 +50%p';
protected $cost = 3000;
protected $consumable = true;
@@ -10,7 +10,7 @@ class che_명마_12_옥란백용구 extends \sammo\BaseStatItem{
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 남은 병력이 적을수록 회피 확률 증가. 최대 +30%p";
$this->info .= "<br>[전투] 남은 병력이 적을수록 회피 확률 증가. 최대 +50%p";
}
public function onCalcStat(General $general, string $statName, $value, $aux = null)
@@ -20,7 +20,7 @@ class che_명마_12_옥란백용구 extends \sammo\BaseStatItem{
$leadership = $general->getLeadership(true, true, true, false);
$crewL = $general->getVar('crew') / 100;
return $value + \sammo\Util::valueFit((1 - $crewL / $leadership) * 0.3, 0, 0.3);
return $value + \sammo\Util::valueFit((1 - $crewL / $leadership) * 0.5, 0, 0.5);
}
return $value;
}
+5 -1
View File
@@ -9,7 +9,7 @@ class che_징병_낙주 extends \sammo\BaseItem{
protected $rawName = '낙주';
protected $name = '낙주(징병)';
protected $info = '[군사] 징·모병비 -30%, 통솔 순수 능력치 보정 +15%';
protected $info = '[군사] 징·모병비 -30%<br>[기타] 통솔 순수 능력치 보정 +15%, 징병/모병/소집해제 시 인구 변동 없음';
protected $cost = 200;
protected $consumable = false;
@@ -18,6 +18,10 @@ class che_징병_낙주 extends \sammo\BaseItem{
if($varType == 'cost') return $value * 0.7;
}
if($turnType == '징집인구' && $varType == 'score'){
return 0;
}
return $value;
}
@@ -9,7 +9,7 @@ class event_전투특기_징병 extends \sammo\BaseItem{
protected $rawName = '비급';
protected $name = '비급(징병)';
protected $info = '[군사] 징·모병비 -50%, 통솔 순수 능력치 보정 +25%';
protected $info = '[군사] 징병/모병 시 훈사 70/84 제공<br>[기타] 통솔 순수 능력치 보정 +25%, 징병/모병/소집해제 시 인구 변동 없음';
protected $cost = 100;
protected $buyable = true;
protected $consumable = false;
@@ -17,7 +17,18 @@ class event_전투특기_징병 extends \sammo\BaseItem{
public function onCalcDomestic(string $turnType, string $varType, float $value, $aux=null):float{
if(in_array($turnType, ['징병', '모병'])){
if($varType == 'cost') return $value * 0.5;
if($varType == 'train' || $varType == 'atmos'){
if($turnType === '징병'){
return 70;
}
else{
return 84;
}
}
}
if($turnType == '징집인구' && $varType == 'score'){
return 0;
}
return $value;
@@ -11,7 +11,7 @@ class event_전투특기_필살 extends \sammo\BaseItem{
protected $rawName = '비급';
protected $name = '비급(필살)';
protected $info = '[전투] 필살 확률 +30%p, 필살 발동시 대상 회피 불가, 필살 계수 항상 최대';
protected $info = '[전투] 필살 확률 +30%p, 필살 발동시 대상 회피 불가, 필살 계수 향상';
protected $cost = 100;
protected $buyable = true;
protected $consumable = false;
@@ -22,8 +22,8 @@ class event_전투특기_필살 extends \sammo\BaseItem{
return $value + 0.3;
}
if($statName === 'criticalDamageRange'){
[, $rangeMax] = $value;
return [$rangeMax, $rangeMax];
[$rangeMin, $rangeMax] = $value;
return [($rangeMin + $rangeMax) / 2, $rangeMax];
}
return $value;
@@ -9,7 +9,7 @@ class che_event_징병 extends \sammo\BaseSpecial{
protected $id = 72;
protected $name = '징병';
protected $info = '[군사] 징·모병비 -50%, 통솔 순수 능력치 보정 +25%';
protected $info = '[군사] 징병/모병 시 훈사 70/84 제공<br>[기타] 통솔 순수 능력치 보정 +25%, 징병/모병/소집해제 시 인구 변동 없음';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
@@ -21,9 +21,20 @@ class che_event_징병 extends \sammo\BaseSpecial{
public function onCalcDomestic(string $turnType, string $varType, float $value, $aux=null):float{
if(in_array($turnType, ['징병', '모병'])){
if($varType == 'cost') return $value * 0.5;
if($varType == 'train' || $varType == 'atmos'){
if($turnType === '징병'){
return 70;
}
else{
return 84;
}
}
}
if($turnType == '징집인구' && $varType == 'score'){
return 0;
}
return $value;
}
@@ -11,7 +11,7 @@ class che_event_필살 extends \sammo\BaseSpecial{
protected $id = 71;
protected $name = '필살';
protected $info = '[전투] 필살 확률 +30%p, 필살 발동시 대상 회피 불가, 필살 계수 항상 최대';
protected $info = '[전투] 필살 확률 +30%p, 필살 발동시 대상 회피 불가, 필살 계수 향상';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
@@ -26,10 +26,10 @@ class che_event_필살 extends \sammo\BaseSpecial{
return $value + 0.30;
}
if($statName === 'criticalDamageRange'){
[, $rangeMax] = $value;
return [$rangeMax, $rangeMax];
[$rangeMin, $rangeMax] = $value;
return [($rangeMin + $rangeMax) / 2, $rangeMax];
}
return $value;
}
+14 -3
View File
@@ -9,7 +9,7 @@ class che_징병 extends \sammo\BaseSpecial{
protected $id = 72;
protected $name = '징병';
protected $info = '[군사] 징·모병비 -50%, 통솔 순수 능력치 보정 +25%';
protected $info = '[군사] 징병/모병 시 훈사 70/84 제공<br>[기타] 통솔 순수 능력치 보정 +25%, 징병/모병/소집해제 시 인구 변동 없음';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
@@ -21,9 +21,20 @@ class che_징병 extends \sammo\BaseSpecial{
public function onCalcDomestic(string $turnType, string $varType, float $value, $aux=null):float{
if(in_array($turnType, ['징병', '모병'])){
if($varType == 'cost') return $value * 0.5;
if($varType == 'train' || $varType == 'atmos'){
if($turnType === '징병'){
return 70;
}
else{
return 84;
}
}
}
if($turnType == '징집인구' && $varType == 'score'){
return 0;
}
return $value;
}
+3 -3
View File
@@ -14,7 +14,7 @@ class che_필살 extends \sammo\BaseSpecial{
protected $id = 71;
protected $name = '필살';
protected $info = '[전투] 필살 확률 +30%p, 필살 발동시 대상 회피 불가, 필살 계수 항상 최대';
protected $info = '[전투] 필살 확률 +30%p, 필살 발동시 대상 회피 불가, 필살 계수 향상';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
@@ -29,8 +29,8 @@ class che_필살 extends \sammo\BaseSpecial{
return $value + 0.30;
}
if($statName === 'criticalDamageRange'){
[, $rangeMax] = $value;
return [$rangeMax, $rangeMax];
[$rangeMin, $rangeMax] = $value;
return [($rangeMin + $rangeMax) / 2, $rangeMax];
}
return $value;
+8 -3
View File
@@ -10,6 +10,7 @@ use sammo\DTO\AuctionBidItemData;
use sammo\DTO\AuctionInfo;
use sammo\Enums\AuctionType;
use sammo\Enums\InheritanceKey;
use sammo\Enums\MessageType;
use sammo\Enums\RankColumn;
use sammo\Enums\ResourceType;
@@ -22,7 +23,7 @@ abstract class Auction
public const COEFF_AUCTION_CLOSE_MINUTES = 24;
public const COEFF_EXTENSION_MINUTES_PER_BID = (1 / 6);
public const COEFF_EXTENSION_MINUTES_LIMIT_BY_BID = 1;
public const COEFF_EXTENSION_MINUTES_LIMIT_BY_BID = 0.5;
public const COEFF_EXTENSION_MINUTES_BY_EXTENSION_QUERY = 1;
public const MIN_AUCTION_CLOSE_MINUTES = 30;
public const MIN_EXTENSION_MINUTES_PER_BID = 1;
@@ -40,6 +41,7 @@ abstract class Auction
if ($namePool === null) {
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
'obfuscatedNamePool',
)));
$namePool = [];
foreach (GameConst::$randGenFirstName as $ch0) {
@@ -244,7 +246,7 @@ abstract class Auction
//TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게..
//TODO: 바로가기를 제공하는 편이 좋을 것 같다.
$msg = new Message(
Message::MSGTYPE_PRIVATE,
MessageType::private,
$src,
$dest,
$reason,
@@ -281,6 +283,9 @@ abstract class Auction
$general = $this->general;
$highestBid = $this->getHighestBid();
if ($highestBid !== null && $amount < $highestBid->amount * 1.01) {
return '현재입찰가보다 1% 높게 입찰해야 합니다.';
}
if ($highestBid !== null && $amount < $highestBid->amount + 10) {
return '현재입찰가보다 10 포인트 높게 입찰해야 합니다.';
}
@@ -505,7 +510,7 @@ abstract class Auction
//TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게..
//TODO: 바로가기를 제공하는 편이 좋을 것 같다.
$msg = new Message(
Message::MSGTYPE_PRIVATE,
MessageType::private,
$src,
$dest,
$failReason,
+2 -1
View File
@@ -7,6 +7,7 @@ use sammo\DTO\AuctionBidItem;
use sammo\DTO\AuctionInfo;
use sammo\DTO\AuctionInfoDetail;
use sammo\Enums\AuctionType;
use sammo\Enums\MessageType;
use sammo\Enums\ResourceType;
abstract class AuctionBasicResource extends Auction
@@ -145,7 +146,7 @@ abstract class AuctionBasicResource extends Auction
//TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게..
//TODO: 바로가기를 제공하는 편이 좋을 것 같다.
$msg = new Message(
Message::MSGTYPE_PRIVATE,
MessageType::private,
$src,
$dest,
"{$this->auctionID}{$hostResName} 경매에 입찰이 없어 취소되었습니다.",
+5 -1
View File
@@ -110,7 +110,11 @@ class AuctionUniqueItem extends Auction
}
$auction = new static($auctionID, $general);
try {
$auction->bid($startAmount, false);
$failReason = $auction->bid($startAmount, false);
if($failReason){
$auction->closeAuction();
return "경매를 시작했지만, 첫 입찰에 실패했습니다: {$failReason}";
}
} catch (\Exception $e) {
//실패해선 안된다.
$msg = $e->getMessage();
@@ -179,6 +179,15 @@ class che_등용수락 extends Command\GeneralCommand{
$db->update('nation', $setScoutNationValues, 'nation=%i', $destNationID);
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
if($general->getNPCType() < 2){
$general->setAuxVar(
InheritanceKey::max_belong->value,
max(
$general->getVar('belong'),
$general->getAuxVar(InheritanceKey::max_belong->value) ?? 0
)
);
}
$general->setVar('permission', 'normal');
$general->setVar('belong', 1);
$general->setVar('officer_level', 1);
@@ -0,0 +1,246 @@
<?php
namespace sammo\Command\General;
use \sammo\DB;
use \sammo\Util;
use \sammo\JosaUtil;
use \sammo\General;
use \sammo\ActionLogger;
use \sammo\GameConst;
use \sammo\GameUnitConst;
use \sammo\LastTurn;
use \sammo\Command;
use \sammo\Json;
use function \sammo\tryUniqueItemLottery;
use function \sammo\getAllNationStaticInfo;
use \sammo\Constraint\ConstraintHelper;
use sammo\Enums\InheritanceKey;
use function sammo\buildNationTypeClass;
use function sammo\genGenericUniqueRNGFromGeneral;
use function sammo\refreshNationStaticInfo;
use function sammo\GetNationColors;
class che_무작위건국 extends Command\GeneralCommand
{
static protected $actionName = '무작위 도시 건국';
static public $reqArg = true;
protected function argTest(): bool
{
if ($this->arg === null) {
return false;
}
$nationName = $this->arg['nationName'] ?? null;
$nationType = $this->arg['nationType'] ?? null;
$colorType = $this->arg['colorType'] ?? null;
if ($nationName === null || $nationType === null || $colorType === null) {
return false;
}
if (!is_string($nationName) || !is_string($nationType) || !is_int($colorType)) {
return false;
}
if (mb_strwidth($nationName) > 18 || $nationName == '') {
return false;
}
if (!key_exists($colorType, GetNationColors())) {
return false;
}
try {
$nationTypeClass = buildNationTypeClass($nationType);
} catch (\InvalidArgumentException $e) {
return false;
}
$this->arg = [
'nationName' => $nationName,
'nationType' => $nationType,
'colorType' => $colorType
];
return true;
}
protected function init()
{
$env = $this->env;
$this->setNation(['gennum', 'aux']);
$relYear = $env['year'] - $env['startyear'];
$this->minConditionConstraints = [
ConstraintHelper::BeOpeningPart($relYear + 1),
ConstraintHelper::ReqNationValue('level', '국가규모', '==', 0, '정식 국가가 아니어야합니다.')
];
}
protected function initWithArg()
{
$env = $this->env;
$relYear = $env['year'] - $env['startyear'];
$nationName = $this->arg['nationName'];
$nationType = $this->arg['nationType'];
$colorType = $this->arg['colorType'];
$this->fullConditionConstraints = [
ConstraintHelper::BeLord(),
ConstraintHelper::WanderingNation(),
ConstraintHelper::ReqNationValue('gennum', '수하 장수', '>=', 2),
ConstraintHelper::BeOpeningPart($relYear + 1),
ConstraintHelper::CheckNationNameDuplicate($nationName),
ConstraintHelper::AllowJoinAction(),
];
}
public function getBrief(): string
{
$nationName = $this->arg['nationName'];
$josaUl = JosaUtil::pick($nationName, '을');
return "{$nationName}{$josaUl} 무작위 도시에 건국";
}
public function getCost(): array
{
return [0, 0];
}
public function getPreReqTurn(): int
{
return 0;
}
public function getPostReqTurn(): int
{
return 0;
}
public function run(\Sammo\RandUtil $rng): bool
{
if (!$this->hasFullConditionMet()) {
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
}
$db = DB::db();
$env = $this->env;
$general = $this->generalObj;
$date = $general->getTurnTime($general::TURNTIME_HM);
$generalName = $general->getName();
$logger = $general->getLogger();
$initYearMonth = Util::joinYearMonth($env['init_year'], $env['init_month']);
$yearMonth = Util::joinYearMonth($env['year'], $env['month']);
if($yearMonth <= $initYearMonth){
$logger->pushGeneralActionLog("다음 턴부터 건국할 수 있습니다. <1>$date</>");
$this->alternative = new che_인재탐색($general, $this->env, null);
return false;
}
$cities = $db->queryFirstColumn('SELECT city FROM city where `level`>=5 and `level`<=6 and nation=0');
if(!$cities){
$logger->pushGeneralActionLog("건국할 수 있는 도시가 없습니다. <1>$date</>");
$this->alternative = new che_해산($general, $this->env, null);
return false;
}
$cityID = $rng->choice($cities);
if($general->getCityID() == $cityID){
$this->setCity();
}
else{
$this->generalObj->setVar('city', $cityID);
$this->setCity();
$db->update('general', [
'city' => $cityID
], 'nation = %i', $general->getNationID());
}
$josaYi = JosaUtil::pick($generalName, '이');
$nationName = $this->arg['nationName'];
$nationType = $this->arg['nationType'];
$colorType = GetNationColors()[$this->arg['colorType']];
$cityName = $this->city['name'];
$josaUl = JosaUtil::pick($nationName, '을');
$nationTypeClass = buildNationTypeClass($nationType);
$nationTypeName = $nationTypeClass->getName();
$logger->pushGeneralActionLog("<D><b>{$nationName}</b></>{$josaUl} 건국하였습니다. <1>$date</>");
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <G><b>{$cityName}</b></>에 국가를 건설하였습니다.");
$josaNationYi = JosaUtil::pick($nationName, '이');
$logger->pushGlobalHistoryLog("<Y><b>【건국】</b></>{$nationTypeName} <D><b>{$nationName}</b></>{$josaNationYi} 새로이 등장하였습니다.");
$logger->pushGeneralHistoryLog("<D><b>{$nationName}</b></>{$josaUl} 건국");
$logger->pushNationalHistoryLog("<Y>{$generalName}</>{$josaYi} <D><b>{$nationName}</b></>{$josaUl} 건국");
$exp = 1000;
$ded = 1000;
$general->addExperience($exp);
$general->addDedication($ded);
$aux = Json::decode($this->nation['aux']) ?? [];
$aux['can_국기변경'] = 1;
$aux['can_무작위수도이전'] = 1;
$db->update('city', [
'nation' => $general->getNationID(),
'conflict' => '{}'
], 'city=%i', $general->getCityID());
$db->update('nation', [
'name' => $nationName,
'color' => $colorType,
'level' => 1,
'type' => $nationType,
'capital' => $general->getCityID(),
'aux' => Json::encode($aux)
], 'nation=%i', $general->getNationID());
refreshNationStaticInfo();
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
$general->checkStatChange();
tryUniqueItemLottery(genGenericUniqueRNGFromGeneral($general), $general, '건국');
$general->applyDB($db);
return true;
}
public function exportJSVars(): array
{
$nationTypes = [];
foreach (GameConst::$availableNationType as $nationType) {
$nationClass = buildNationTypeClass($nationType);
$nationTypes[$nationType] = [
'type' => $nationType,
'name' => $nationClass->getName(),
'pros' => $nationClass::$pros,
'cons' => $nationClass::$cons
];
}
return [
'procRes' => [
'available건국' => count(getAllNationStaticInfo()) < $this->env['maxnation'],
'nationTypes' => $nationTypes,
'colors' => GetNationColors(),
]
];
}
}
@@ -62,8 +62,6 @@ class che_소집해제 extends Command\GeneralCommand{
$general = $this->generalObj;
$date = $general->getTurnTime($general::TURNTIME_HM);
$crew = $general->getVar('crew');
$logger = $general->getLogger();
$logger->pushGeneralActionLog("병사들을 <R>소집해제</>하였습니다. <1>$date</>");
@@ -71,8 +69,10 @@ class che_소집해제 extends Command\GeneralCommand{
$exp = 70;
$ded = 100;
$crewUp = $general->onCalcDomestic('징집인구', 'score', $general->getVar('crew'));
$db->update('city', [
'pop'=>$db->sqleval('pop + %i', $crew)
'pop'=>$db->sqleval('pop + %i', $crewUp)
], 'city=%i', $general->getCityID());
$general->setVar('crew', 0);
+6
View File
@@ -10,6 +10,7 @@ use \sammo\{
use \sammo\Constraint\ConstraintHelper;
use function sammo\tryUniqueItemLottery;
use function sammo\CheckHall;
class che_은퇴 extends Command\GeneralCommand{
static protected $actionName = '은퇴';
@@ -59,12 +60,17 @@ class che_은퇴 extends Command\GeneralCommand{
}
$db = DB::db();
$env = $this->env;
$general = $this->generalObj;
$date = $general->getTurnTime($general::TURNTIME_HM);
$logger = $general->getLogger();
if ($env['isunited'] == 0) {
CheckHall($general->getID());
}
$general->rebirth();
$logger->pushGeneralActionLog("은퇴하였습니다. <1>$date</>");
+11 -6
View File
@@ -184,10 +184,13 @@ class che_징병 extends Command\GeneralCommand
$logger = $general->getLogger();
$setTrain = $general->onCalcDomestic(static::$actionName, 'train', static::$defaultTrain);
$setAtmos = $general->onCalcDomestic(static::$actionName, 'atmos', static::$defaultAtmos);
if ($reqCrewType->id == $currCrewType->id && $currCrew > 0) {
$logger->pushGeneralActionLog("{$crewTypeName} <C>{$reqCrewText}</>명을 추가{$this->getName()}했습니다. <1>$date</>");
$train = ($currCrew * $general->getVar('train') + $reqCrew * static::$defaultTrain) / ($currCrew + $reqCrew);
$atmos = ($currCrew * $general->getVar('atmos') + $reqCrew * static::$defaultAtmos) / ($currCrew + $reqCrew);
$train = ($currCrew * $general->getVar('train') + $reqCrew * $setTrain) / ($currCrew + $reqCrew);
$atmos = ($currCrew * $general->getVar('atmos') + $reqCrew * $setAtmos) / ($currCrew + $reqCrew);
$general->increaseVar('crew', $reqCrew);
$general->setVar('train', $train);
@@ -196,15 +199,17 @@ class che_징병 extends Command\GeneralCommand
$logger->pushGeneralActionLog("{$crewTypeName} <C>{$reqCrewText}</>명을 {$this->getName()}했습니다. <1>$date</>");
$general->setVar('crewtype', $reqCrewType->id);
$general->setVar('crew', $reqCrew);
$general->setVar('train', static::$defaultTrain);
$general->setVar('atmos', static::$defaultAtmos);
$general->setVar('train', $setTrain);
$general->setVar('atmos', $setAtmos);
}
$newTrust = Util::valueFit($this->city['trust'] - ($reqCrew / $this->city['pop']) / static::$costOffset * 100, 0);
$reqCrewDown = $general->onCalcDomestic('징집인구', 'score', $reqCrew);
$newTrust = Util::valueFit($this->city['trust'] - ($reqCrewDown / $this->city['pop']) / static::$costOffset * 100, 0);
$db->update('city', [
'trust' => $newTrust,
'pop' => $this->city['pop'] - $reqCrew
'pop' => $this->city['pop'] - $reqCrewDown
], 'city=%i', $general->getCityID());
$exp = Util::round($reqCrew / 100);
+9
View File
@@ -113,6 +113,15 @@ class che_하야 extends Command\GeneralCommand{
$general->setVar('troop', 0);
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
if($general->getNPCType() < 2){
$general->setAuxVar(
InheritanceKey::max_belong->value,
max(
$general->getVar('belong'),
$general->getAuxVar(InheritanceKey::max_belong->value) ?? 0
)
);
}
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
$general->checkStatChange();
+1
View File
@@ -94,6 +94,7 @@ class che_화계 extends Command\GeneralCommand
$prob = $maxGenScore / GameConst::$sabotageProbCoefByStat;
$prob += $probCorrection;
$prob += (log(count($destCityGeneralList) + 1, 2) - 1.25) * GameConst::$sabotageDefenceCoefByGeneralCnt;
$prob += $destCity['secu'] / $destCity['secu_max'] / 5; //최대 20%p
$prob += $destCity['supply'] ? 0.1 : 0;
+2 -1
View File
@@ -19,6 +19,7 @@ use function \sammo\GetImageURL;
use \sammo\Constraint\Constraint;
use \sammo\Constraint\ConstraintHelper;
use sammo\Enums\MessageType;
class che_몰수 extends Command\NationCommand
{
@@ -186,7 +187,7 @@ class che_몰수 extends Command\NationCommand
GetImageURL($destGeneral->getVar('imgsvr'), $destGeneral->getVar('picture'))
);
$msg = new Message(
Message::MSGTYPE_PUBLIC,
MessageType::public,
$src,
$src,
$text,
@@ -0,0 +1,165 @@
<?php
namespace sammo\Command\Nation;
use \sammo\DB;
use \sammo\Util;
use \sammo\JosaUtil;
use \sammo\General;
use \sammo\DummyGeneral;
use \sammo\ActionLogger;
use \sammo\GameConst;
use \sammo\LastTurn;
use \sammo\GameUnitConst;
use \sammo\Command;
use \sammo\MessageTarget;
use \sammo\Message;
use \sammo\CityConst;
use \sammo\Constraint\Constraint;
use \sammo\Constraint\ConstraintHelper;
use sammo\Enums\InheritanceKey;
use sammo\Event\Action;
use sammo\Json;
class che_무작위수도이전 extends Command\NationCommand
{
static protected $actionName = '무작위 수도 이전';
protected function argTest(): bool
{
$this->arg = [];
return true;
}
protected function init()
{
$env = $this->env;
$relYear = $env['year'] - $env['startyear'];
$this->setCity();
$this->setNation(['capital', 'aux']);
$this->fullConditionConstraints = [
ConstraintHelper::OccupiedCity(),
ConstraintHelper::BeLord(),
ConstraintHelper::SuppliedCity(),
ConstraintHelper::BeOpeningPart($relYear + 1),
ConstraintHelper::ReqNationAuxValue("can_무작위수도이전", 0, '>', 0, '더이상 변경이 불가능합니다.')
];
}
public function getCommandDetailTitle():string{
$name = $this->getName();
$reqTurn = $this->getPreReqTurn()+1;
return "{$name}/{$reqTurn}";
}
public function getCost(): array
{
return [0, 0];
}
public function getPreReqTurn(): int
{
return 1;
}
public function getPostReqTurn(): int
{
return 0;
}
public function run(\Sammo\RandUtil $rng): bool
{
if (!$this->hasFullConditionMet()) {
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
}
$db = DB::db();
$general = $this->generalObj;
$generalID = $general->getID();
$generalName = $general->getName();
$date = $general->getTurnTime($general::TURNTIME_HM);
$year = $this->env['year'];
$month = $this->env['month'];
$logger = $general->getLogger();
$oldCityID = $this->nation['capital'];
$cities = $db->queryFirstColumn('SELECT city FROM city where `level`>=5 and `level`<=6 and nation=0');
if (!$cities) {
$logger->pushGeneralActionLog("이동할 수 있는 도시가 없습니다. <1>$date</>");
return false;
}
$destCityID = $rng->choice($cities);
$this->setDestCity($destCityID, true);
$destCity = $this->destCity;
$destCityID = $destCity['city'];
$destCityName = $destCity['name'];
$nationID = $general->getNationID();
$nationName = $this->nation['name'];
$josaRo = JosaUtil::pick($destCityName, '로');
$general->addExperience(5 * ($this->getPreReqTurn() + 1));
$general->addDedication(5 * ($this->getPreReqTurn() + 1));
$josaYi = JosaUtil::pick($generalName, '이');
$josaYiNation = JosaUtil::pick($nationName, '이');
$aux = Json::decode($this->nation['aux']);
$aux["can_무작위수도이전"] -= 1;
$db->update('city', [
'nation' => $nationID,
'conflict' => '{}'
], 'city=%i', $destCityID);
$db->update('nation', [
'capital' => $destCityID,
'aux'=>Json::encode($aux),
], 'nation=%i', $nationID);
$db->update('city', [
'nation' => 0,
'front' => 0,
'conflict' => '{}',
'officer_set' => 0,
], 'city=%i', $oldCityID);
$general->setVar('city', $destCityID);
$generalList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no!=%i', $general->getNationID(), $general->getID());
if ($generalList) {
$db->update('general', [
'city' => $destCityID
], 'no IN %li', $generalList);
}
foreach ($generalList as $targetGeneralID) {
$targetLogger = new ActionLogger($targetGeneralID, $general->getNationID(), $year, $month);
$targetLogger->pushGeneralActionLog("국가 수도를 <G><b>{$destCityName}</b></>{$josaRo} 옮겼습니다.", ActionLogger::PLAIN);
$targetLogger->flush();
}
\sammo\refreshNationStaticInfo();
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
$logger->pushGeneralActionLog("<G><b>{$destCityName}</b></>{$josaRo} 국가를 옮겼습니다. <1>$date</>");
$logger->pushGeneralHistoryLog("<G><b>{$destCityName}</b></>{$josaRo} <M>무작위 수도 이전</>");
$logger->pushNationalHistoryLog("<Y>{$generalName}</>{$josaYi} <G><b>{$destCityName}</b></>{$josaRo} <M>무작위 수도 이전</>");
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <G><b>{$destCityName}</b></>{$josaRo} <M>수도 이전</>하였습니다.");
$logger->pushGlobalHistoryLog("<S><b>【무작위 수도 이전】</b></><D><b>{$nationName}</b></>{$josaYiNation} <G><b>{$destCityName}</b></>{$josaRo} <M>수도 이전</>하였습니다.");
$this->setResultTurn(new LastTurn($this->getName(), $this->arg, 0));
$general->applyDB($db);
return true;
}
}
@@ -112,7 +112,7 @@ class che_불가침수락 extends Command\NationCommand
$month = $this->arg['month'];
$currentMonth = $env['year'] * 12 + $env['month'] - 1;
$reqMonth = $year * 12 + $month - 1;
$reqMonth = $year * 12 + $month;
$nationID = $this->nation['nation'];
@@ -199,7 +199,7 @@ class che_불가침수락 extends Command\NationCommand
$destLogger = $this->destGeneralObj->getLogger();
$currentMonth = $env['year'] * 12 + $env['month'] - 1;
$reqMonth = $year * 12 + $month - 1;
$reqMonth = $year * 12 + $month;
$db->update(
'diplomacy',
@@ -22,6 +22,7 @@ use function \sammo\getNationStaticInfo;
use \sammo\Constraint\Constraint;
use \sammo\Constraint\ConstraintHelper;
use sammo\Enums\MessageType;
class che_불가침제의 extends Command\NationCommand
{
@@ -202,7 +203,7 @@ class che_불가침제의 extends Command\NationCommand
$josaWa = JosaUtil::pick($nationName, '와');
$msg = new DiplomaticMessage(
Message::MSGTYPE_DIPLOMACY,
MessageType::diplomacy,
$src,
$dest,
"{$nationName}{$josaWa} {$year}{$month}월까지 불가침 제의 서신",
@@ -20,6 +20,7 @@ use function \sammo\GetImageURL;
use \sammo\Constraint\Constraint;
use \sammo\Constraint\ConstraintHelper;
use sammo\Enums\MessageType;
class che_불가침파기제의 extends Command\NationCommand{
static protected $actionName = '불가침 파기 제의';
@@ -150,7 +151,7 @@ class che_불가침파기제의 extends Command\NationCommand{
$validUntil->add(new \DateInterval("PT{$validMinutes}M"));
$msg = new DiplomaticMessage(
Message::MSGTYPE_DIPLOMACY,
MessageType::diplomacy,
$src,
$dest,
"{$nationName}의 불가침 파기 제의 서신",
@@ -21,6 +21,7 @@ use function \sammo\GetImageURL;
use \sammo\Constraint\Constraint;
use \sammo\Constraint\ConstraintHelper;
use sammo\Enums\MessageType;
class che_선전포고 extends Command\NationCommand
{
@@ -175,7 +176,7 @@ class che_선전포고 extends Command\NationCommand
$destNation['color']
);
$msg = new Message(
Message::MSGTYPE_NATIONAL,
MessageType::national,
$src,
$dest,
$text,
@@ -131,7 +131,7 @@ class che_의병모집 extends Command\NationCommand
$gameStor = KVStorage::getStorage($db, 'game_env'); //TODO: 차라리 env가 이거여야..?
$avgGenCnt = $db->queryFirstField('SELECT avg(gennum) FROM nation WHERE level > 0');
$createGenCnt = 5 + Util::round($avgGenCnt / 10);
$createGenCnt = 3 + Util::round($avgGenCnt / 8);
$createGenIdx = $gameStor->npccount + 1;
$lastCreatGenIdx = $createGenIdx + $createGenCnt;
@@ -156,6 +156,7 @@ class che_의병모집 extends Command\NationCommand
$newNPC->setNPCType(4);
$newNPC->setMoney(1000, 1000);
$newNPC->setSpecYear(19, 19);
$newNPC->setExpDed($avgGen['exp'], $avgGen['ded']);
$newNPC->fillRemainSpecAsRandom($pickTypeList, $avgGen, $env);
$newNPC->build($this->env);
@@ -20,6 +20,7 @@ use function \sammo\GetImageURL;
use \sammo\Constraint\Constraint;
use \sammo\Constraint\ConstraintHelper;
use sammo\Enums\MessageType;
class che_종전제의 extends Command\NationCommand{
static protected $actionName = '종전 제의';
@@ -148,7 +149,7 @@ class che_종전제의 extends Command\NationCommand{
$validUntil->add(new \DateInterval("PT{$validMinutes}M"));
$msg = new DiplomaticMessage(
Message::MSGTYPE_DIPLOMACY,
MessageType::diplomacy,
$src,
$dest,
"{$nationName}의 종전 제의 서신",
@@ -171,6 +171,9 @@ class che_초토화 extends Command\NationCommand{
'pop'=>$db->sqleval('greatest(pop_max*0.1, pop*0.2)'),
'agri'=>$db->sqleval('greatest(agri_max*0.1, agri*0.2)'),
'comm'=>$db->sqleval('greatest(comm_max*0.1, comm*0.2)'),
'secu'=>$db->sqleval('greatest(secu_max*0.1, secu*0.2)'),
'def'=>$db->sqleval('greatest(def_max*0.1, def*0.2)'),
'wall'=>$db->sqleval('greatest(wall_max*0.1, wall*0.5)'),
'nation'=>0,
'front'=>0,
'conflict'=>'{}'
+14 -3
View File
@@ -59,6 +59,9 @@ class che_피장파장 extends Command\NationCommand
if (!in_array($commandType, GameConst::$availableChiefCommand['전략'])) {
return false;
}
if($commandType == Util::getClassNameFromObj($this)){
return false;
}
$this->arg = [
@@ -75,7 +78,7 @@ class che_피장파장 extends Command\NationCommand
$env = $this->env;
$this->setCity();
$this->setNation();
$this->setNation(['strategic_cmd_limit']);
$this->minConditionConstraints = [
ConstraintHelper::OccupiedCity(),
@@ -113,6 +116,7 @@ class che_피장파장 extends Command\NationCommand
[0, 1],
'선포, 전쟁중인 상대국에게만 가능합니다.'
),
ConstraintHelper::AvailableStrategicCommand(),
];
}
@@ -120,8 +124,9 @@ class che_피장파장 extends Command\NationCommand
{
$name = $this->getName();
$reqTurn = $this->getPreReqTurn() + 1;
$postReqTurn = $this->getPostReqTurn();
return "{$name}/{$reqTurn}턴(대상 재사용 대기 {$this->getTargetPostReqTurn()})";
return "{$name}/{$reqTurn}턴(재사용 대기 $postReqTurn, 대상 재사용 대기 {$this->getTargetPostReqTurn()})";
}
public function getCost(): array
@@ -136,7 +141,7 @@ class che_피장파장 extends Command\NationCommand
public function getPostReqTurn(): int
{
return 0;
return 8;
}
public function getTargetPostReqTurn(): int
@@ -251,7 +256,13 @@ class che_피장파장 extends Command\NationCommand
$oneAvailableCommandName = null;
$thisClassName = Util::getClassNameFromObj($this);
foreach (GameConst::$availableChiefCommand['전략'] as $commandType) {
if($commandType == $thisClassName){
continue;
}
$cmd = buildNationCommandClass($commandType, $generalObj, $this->env, new LastTurn());
$cmdName = $cmd->getName();
$remainTurn = 0;
+6 -6
View File
@@ -2,13 +2,13 @@
namespace sammo\DTO;
use sammo\DTO\Attr\Convert;
use sammo\DTO\Attr\JsonString;
use sammo\DTO\Attr\NullIsUndefined;
use sammo\DTO\Attr\RawName;
use sammo\DTO\Converter\DateTimeConverter;
use LDTO\Attr\Convert;
use LDTO\Attr\JsonString;
use LDTO\Attr\NullIsUndefined;
use LDTO\Attr\RawName;
use LDTO\Converter\DateTimeConverter;
class AuctionBidItem extends DTO
class AuctionBidItem extends \LDTO\DTO
{
public function __construct(
#[NullIsUndefined]
+2 -2
View File
@@ -2,9 +2,9 @@
namespace sammo\DTO;
use sammo\DTO\Attr\NullIsUndefined;
use LDTO\Attr\NullIsUndefined;
class AuctionBidItemData extends DTO
class AuctionBidItemData extends \LDTO\DTO
{
public function __construct(
#[NullIsUndefined]
+6 -6
View File
@@ -2,15 +2,15 @@
namespace sammo\DTO;
use sammo\DTO\Attr\Convert;
use sammo\DTO\Attr\JsonString;
use sammo\DTO\Attr\NullIsUndefined;
use sammo\DTO\Attr\RawName;
use sammo\DTO\Converter\DateTimeConverter;
use LDTO\Attr\Convert;
use LDTO\Attr\JsonString;
use LDTO\Attr\NullIsUndefined;
use LDTO\Attr\RawName;
use LDTO\Converter\DateTimeConverter;
use sammo\Enums\AuctionType;
use sammo\Enums\ResourceType;
class AuctionInfo extends DTO
class AuctionInfo extends \LDTO\DTO
{
public function __construct(
#[NullIsUndefined]
+4 -4
View File
@@ -2,11 +2,11 @@
namespace sammo\DTO;
use sammo\DTO\Attr\Convert;
use sammo\DTO\Attr\NullIsUndefined;
use sammo\DTO\Converter\DateTimeConverter;
use LDTO\Attr\Convert;
use LDTO\Attr\NullIsUndefined;
use LDTO\Converter\DateTimeConverter;
class AuctionInfoDetail extends DTO
class AuctionInfoDetail extends \LDTO\DTO
{
public function __construct(
public string $title,
+3 -3
View File
@@ -2,13 +2,13 @@
namespace sammo\DTO;
use sammo\DTO\Attr\Convert;
use sammo\DTO\Converter\MapConverter;
use LDTO\Attr\Convert;
use LDTO\Converter\MapConverter;
use sammo\DTO\SelectItem;
//https://json2dto.atymic.dev/
class BettingInfo extends DTO
class BettingInfo extends \LDTO\DTO
{
public function __construct(
public int $id,
+3 -3
View File
@@ -2,10 +2,10 @@
namespace sammo\DTO;
use sammo\DTO\Attr\NullIsUndefined;
use sammo\DTO\Attr\RawName;
use LDTO\Attr\NullIsUndefined;
use LDTO\Attr\RawName;
class BettingItem extends DTO
class BettingItem extends \LDTO\DTO
{
public function __construct(
#[RawName('id')]
+3 -3
View File
@@ -2,10 +2,10 @@
namespace sammo\DTO;
use sammo\DTO\Attr\Convert;
use sammo\DTO\Converter\MapConverter;
use LDTO\Attr\Convert;
use LDTO\Converter\MapConverter;
class SelectItem extends DTO
class SelectItem extends \LDTO\DTO
{
public function __construct(
public string $title,
+3 -3
View File
@@ -2,10 +2,10 @@
namespace sammo\DTO;
use sammo\DTO\Attr\NullIsUndefined;
use sammo\DTO\Attr\RawName;
use LDTO\Attr\NullIsUndefined;
use LDTO\Attr\RawName;
class VoteComment extends DTO
class VoteComment extends \LDTO\DTO
{
public function __construct(
#[NullIsUndefined]
+1 -1
View File
@@ -2,7 +2,7 @@
namespace sammo\DTO;
class VoteInfo extends DTO
class VoteInfo extends \LDTO\DTO
{
public function __construct(
public int $id,
+6 -4
View File
@@ -1,6 +1,8 @@
<?php
namespace sammo;
use sammo\Enums\MessageType;
class DiplomaticMessage extends Message{
const ACCEPTED = 1;
@@ -18,7 +20,7 @@ class DiplomaticMessage extends Message{
protected $validDiplomacy = true;
public function __construct(
string $msgType,
MessageType $msgType,
MessageTarget $src,
MessageTarget $dest,
string $msg,
@@ -27,7 +29,7 @@ class DiplomaticMessage extends Message{
array $msgOption
)
{
if ($msgType !== self::MSGTYPE_DIPLOMACY){
if ($msgType !== MessageType::diplomacy){
throw new \InvalidArgumentException('DiplomaticMessage msgType');
}
@@ -208,7 +210,7 @@ class DiplomaticMessage extends Message{
$josaYi = JosaUtil::pick($this->src->nationName, '이');
$newMsg = new Message(
self::MSGTYPE_NATIONAL,
MessageType::national,
$this->dest,
$this->src,
"【외교】{$year}{$month}월: {$this->src->nationName}{$josaYi} {$this->dest->nationName}에게 제안한 {$this->diplomacyDetail}",
@@ -224,7 +226,7 @@ class DiplomaticMessage extends Message{
$newMsg->send();
$newMsg = new Message(
self::MSGTYPE_DIPLOMACY,
MessageType::diplomacy,
$this->dest,
$this->src,
"【외교】{$year}{$month}월: {$this->src->nationName}{$josaYi} {$this->dest->nationName}에게 제안한 {$this->diplomacyDetail}",
+14
View File
@@ -0,0 +1,14 @@
<?php
namespace sammo\Enums;
/**
* API 호출 결과가 false이면서, 대상 API가 처리할 수 없는 추가 동작이 있는 경우 사용.
* 예시: 턴을 예약해야 하지만, 장수가 사망하여 게이트웨이로 이동해야함.
*/
enum APIRecoveryType: string{
case Login = 'login';//로그인 재시도부터 시작한다
case TwoFactorAuth = '2fa';//로그인은 가능하지만 인증코드 입력이 필요하다
case Gateway = 'gateway';//로그인 완료. 게임 서버 리스트를 띄워야한다
case GameLogin = 'game_login';//서버 업데이트 등으로 다시 게임 정보 수신 필요
case GameQuota = 'game_quota';//접속 제한
}
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace sammo\Enums;
/**
* City Table column
* schemal.sql과 일치
*/
enum CityColumn: string{
case city = 'city';
case name = 'name';
case level = 'level';
case nation = 'nation';
case supply = 'supply';
case front = 'front';
case pop = 'pop';
case pop_max = 'pop_max';
case agri = 'agri';
case agri_max = 'agri_max';
case comm = 'comm';
case comm_max = 'comm_max';
case secu = 'secu';
case secu_max = 'secu_max';
case trust = 'trust';
case trade = 'trade';
case dead = 'dead';
case def = 'def';
case def_max = 'def_max';
case wall = 'wall';
case wall_max = 'wall_max';
case officer_set = 'officer_set';
case state = 'state';
case region = 'region';
case term = 'term';
case conflict = 'conflict';
}
+84
View File
@@ -0,0 +1,84 @@
<?php
namespace sammo\Enums;
/**
* General Table column
* schemal.sql과 일치
*/
enum GeneralColumn: string{
case no = 'no';
case owner = 'owner';
case npcmsg = 'npcmsg';
case npc = 'npc';
case npc_org = 'npc_org';
case affinity = 'affinity';
case bornyear = 'bornyear';
case deadyear = 'deadyear';
case newmsg = 'newmsg';
case con = 'con';
case connect = 'connect';
case refresh = 'refresh';
case logcnt = 'logcnt';
case refcnt = 'refcnt';
case picture = 'picture';
case imgsvr = 'imgsvr';
case name = 'name';
case owner_name = 'owner_name';
case nation = 'nation';
case city = 'city';
case troop = 'troop';
case leadership = 'leadership';
case leadership_exp = 'leadership_exp';
case strength = 'strength';
case strength_exp = 'strength_exp';
case intel = 'intel';
case intel_exp = 'intel_exp';
case injury = 'injury';
case experience = 'experience';
case dedication = 'dedication';
case dex1 = 'dex1';
case dex2 = 'dex2';
case dex3 = 'dex3';
case dex4 = 'dex4';
case dex5 = 'dex5';
case officer_level = 'officer_level';
case officer_city = 'officer_city';
case permission = 'permission';
case gold = 'gold';
case rice = 'rice';
case crew = 'crew';
case crewtype = 'crewtype';
case train = 'train';
case atmos = 'atmos';
case weapon = 'weapon';
case book = 'book';
case horse = 'horse';
case item = 'item';
case turntime = 'turntime';
case recent_war = 'recent_war';
case makelimit = 'makelimit';
case killturn = 'killturn';
case lastconnect = 'lastconnect';
case lastrefresh = 'lastrefresh';
case ip = 'ip';
case block = 'block';
case dedlevel = 'dedlevel';
case explevel = 'explevel';
case age = 'age';
case startage = 'startage';
case belong = 'belong';
case betray = 'betray';
case personal = 'personal';
case special = 'special';
case specage = 'specage';
case special2 = 'special2';
case specage2 = 'specage2';
case defence_train = 'defence_train';
case tnmt = 'tnmt';
case myset = 'myset';
case tournament = 'tournament';
case newvote = 'newvote';
case last_turn = 'last_turn';
case aux = 'aux';
case penalty = 'penalty';
}
+12
View File
@@ -0,0 +1,12 @@
<?php
namespace sammo\Enums;
enum MessageType: string
{
case private = 'private';
case public = 'public';
case national = 'national';
case diplomacy = 'diplomacy';
//TODO: System을 정식으로 추가해야함.
}
@@ -0,0 +1,20 @@
<?php
namespace sammo\Event\Action;
use sammo\DB;
class AddGlobalBetray extends \sammo\Event\Action
{
public function __construct(private int $cnt = 1, private int $ifMax = 0)
{
}
public function run(array $env)
{
$db = DB::db();
$db->update('general', [
'betray' => $db->sqleval('betray + %i', $this->cnt),
], 'betray <= %i', $this->ifMax);
}
}
+1 -1
View File
@@ -25,7 +25,7 @@ class CreateManyNPC extends \sammo\Event\Action
protected function generateNPC($env, int $cnt)
{
$pickTypeList = ['무' => 1, '지' => 1];
$pickTypeList = ['무' => 0.333, '지' => 0.333, '지' => 0.334];
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
+108
View File
@@ -0,0 +1,108 @@
<?php
namespace sammo\Event\Action;
use sammo\ActionLogger;
use sammo\CityConst;
use sammo\DB;
use sammo\KVStorage;
use sammo\Util;
use sammo\General;
use sammo\JosaUtil;
use sammo\LiteHashDRBG;
use sammo\RandUtil;
use sammo\UniqueConst;
class LostUniqueItem extends \sammo\Event\Action
{
public function __construct(
private float $lostProb = 0.1,
) {
}
public function run(array $env)
{
$db = DB::db();
$generalIDList = $db->queryFirstColumn("SELECT `no` FROM general WHERE npc <= 1");
if (!$generalIDList) {
return;
}
$generals = General::createGeneralObjListFromDB($generalIDList);
$lostItems = [];
$totalLostCnt = 0;
$year = $env['year'];
$month = $env['month'];
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
'LostUniqueItem',
$year,
$month,
)));
$maxLostByGenCnt = 0;
$maxLostGenList = [];
foreach ($generals as $general) {
$itemList = $general->getItems();
$didLoseItem = false;
$lostByGenCnt = 0;
foreach ($itemList as $itemType => $item) {
if ($item->isBuyable()) {
continue;
}
$logger = $general->getLogger();
if ($rng->nextBool($this->lostProb)) {
$itemName = $item->getName();
$itemRawName = $item->getRawName();
$josaUl = JosaUtil::pick($itemRawName, '을');
$lostItems[$itemName] = 1;
$totalLostCnt++;
$lostByGenCnt++;
$general->setItem($itemType, 'None');
$didLoseItem = true;
$logger->pushGeneralActionLog("<C>{$itemName}</>{$josaUl} 잃었습니다.");
}
}
if (!$didLoseItem) {
continue;
}
$general->applyDB($db);
if ($maxLostByGenCnt < $lostByGenCnt) {
$maxLostByGenCnt = $lostByGenCnt;
$maxLostGenList = [$general->getName()];
} else if ($maxLostByGenCnt === $lostByGenCnt) {
$maxLostGenList[] = $general->getName();
}
}
$logger = new ActionLogger(0, 0, $year, $month);
if ($totalLostCnt == 0) {
$logger->pushGlobalHistoryLog("<R><b>【망실】</b></>어떤 아이템도 잃지 않았습니다!");
} else {
$genCnt = count($maxLostGenList);
if($genCnt > 4){
$maxLostGenList = array_slice($maxLostGenList, 0, 4);
}
$maxLostGenListStr = implode(', ', $maxLostGenList);
if($genCnt > 4){
$maxLostGenListStr .= ' 외 ' . ($genCnt - 4) . '명';
}
$josaYi = JosaUtil::pick($maxLostGenListStr, '이');
$logger->pushGlobalHistoryLog("<R><b>【망실】</b></>불운하게도 <Y>{$maxLostGenListStr}</>{$josaYi} 한 번에 유니크 <C>{$maxLostByGenCnt}</>종을 잃었습니다! (총 <C>{$totalLostCnt}</>개)");
}
$logger->flush();
}
}
+2 -1
View File
@@ -9,6 +9,7 @@ use \sammo\Util;
use \sammo\DB;
use sammo\DTO\BettingInfo;
use sammo\DTO\SelectItem;
use sammo\Enums\MessageType;
use sammo\Json;
use sammo\KVStorage;
use sammo\Message;
@@ -138,7 +139,7 @@ class OpenNationBetting extends \sammo\Event\Action
GetImageURL($general['imgsvr'], $general['picture'])
);
$msg = new Message(
Message::MSGTYPE_PRIVATE,
MessageType::private,
$src,
$dest,
$text,
+16 -1
View File
@@ -46,6 +46,8 @@ class GameConstBase
public static $sabotageDefaultProb = 0.35;
/** @var int 계략시 확률 가중치(수치가 클수록 변화가 적음 : (지력차/$firing + $basefiring)*/
public static $sabotageProbCoefByStat = 300;
/** @var float 인원수 별 계략 방어 가중치 */
public static $sabotageDefenceCoefByGeneralCnt = 0.04;
/** @var int 계략시 최소 수치 감소량*/
public static $sabotageDamageMin = 100;
/** @var int 계략시 최대 수치 감소량*/
@@ -202,6 +204,11 @@ class GameConstBase
[20, 4]
];
public static $minTurnDieOnPrestart = 2;
public static $uniqueTrialCoef = 1;
public static $maxUniqueTrialProb = 0.25;
public static $maxAvailableWarSettingCnt = 10;
public static $incAvailableWarSettingCnt = 2;
@@ -368,9 +375,9 @@ class GameConstBase
'che_의병모집',
'che_이호경식',
'che_급습',
'che_피장파장',
],
'기타' => [
'che_피장파장',
'che_국기변경',
'che_국호변경',
]
@@ -431,5 +438,13 @@ class GameConstBase
["NoticeToHistoryLog", "<S>출병 제한이 풀렸습니다.</>", ActionLogger::EVENT_YEAR_MONTH],
["DeleteEvent"]
],
[
"month", 2000,
["DateRelative", "==", 4, 1],
["NoticeToHistoryLog", "<S>이제부터 하야, 망명시 패널티가 적용됩니다.</>", ActionLogger::EVENT_YEAR_MONTH],
["AddGlobalBetray", 1, 0],
["AddGlobalBetray", 1, 1],
["DeleteEvent"]
],
];
}
+13 -13
View File
@@ -115,16 +115,16 @@ class GameUnitConstBase{
[self::T_CAVALRY=>1.2, self::T_FOOTMAN=>0.8, self::T_SIEGE=>1.2],
[self::T_CAVALRY=>0.8, self::T_FOOTMAN=>1.2, self::T_SIEGE=>0.8],
['표준적인 궁병입니다.','궁병은 선제사격을 하는 병종입니다.'],
null, ['che_궁병선제사격']
null, ['che_선제사격시도', 'che_선제사격발동']
],
[
1201, self::T_ARCHER, '궁기병',
100, 100, 8, 20, 0, 11, 12,
1000, null, ['동이'], 0,
[self::T_CAVALRY=>1.2, self::T_FOOTMAN=>0.8, self::T_SIEGE=>1.2],
[self::T_CAVALRY=>0.8, self::T_FOOTMAN=>1.2, self::T_SIEGE=>0.8],
['말을 타고 잘 피합니다.'],
null, ['che_궁병선제사격']
[self::T_CAVALRY=>1.2, self::T_FOOTMAN=>0.9, self::T_SIEGE=>1.2],
[self::T_CAVALRY=>0.8, self::T_FOOTMAN=>1.1, self::T_SIEGE=>0.8],
['말을 타고 잘 피합니다. 특히 다른 궁병보다 보병에게 조금 더 강합니다.'],
null, ['che_선제사격시도', 'che_선제사격발동']
],
[
1202, self::T_ARCHER, '연노병',
@@ -133,7 +133,7 @@ class GameUnitConstBase{
[self::T_CAVALRY=>1.2, self::T_FOOTMAN=>0.8, self::T_SIEGE=>1.2],
[self::T_CAVALRY=>0.8, self::T_FOOTMAN=>1.2, self::T_SIEGE=>0.8],
['화살을 연사합니다.'],
null, ['che_궁병선제사격']
null, ['che_선제사격시도', 'che_선제사격발동']
],
[
1203, self::T_ARCHER, '강궁병',
@@ -142,7 +142,7 @@ class GameUnitConstBase{
[self::T_CAVALRY=>1.2, self::T_FOOTMAN=>0.8, self::T_SIEGE=>1.2],
[self::T_CAVALRY=>0.8, self::T_FOOTMAN=>1.2, self::T_SIEGE=>0.8],
['강건한 궁병입니다.'],
null, ['che_궁병선제사격']
null, ['che_선제사격시도', 'che_선제사격발동']
],
[
1204, self::T_ARCHER, '석궁병',
@@ -151,7 +151,7 @@ class GameUnitConstBase{
[self::T_CAVALRY=>1.2, self::T_FOOTMAN=>0.8, self::T_SIEGE=>1.2],
[self::T_CAVALRY=>0.8, self::T_FOOTMAN=>1.2, self::T_SIEGE=>0.8],
['강력한 화살을 쏩니다.'],
null, ['che_궁병선제사격']
null, ['che_선제사격시도', 'che_선제사격발동']
],
[
@@ -316,7 +316,7 @@ class GameUnitConstBase{
[self::T_FOOTMAN=>1.25, self::T_ARCHER=>1.25, self::T_CAVALRY=>1.25, self::T_WIZARD=>1.25, self::T_CASTLE=>1.8, 1106=>1.112],
[self::T_FOOTMAN=>1.2, self::T_ARCHER=>1.2, self::T_CAVALRY=>1.2, self::T_WIZARD=>1.2],
['높은 구조물 위에서 공격합니다.'],
['che_성벽부상무효'], null
['che_성벽부상무효'], ['che_선제사격시도', 'che_선제사격발동']
],
[
1501, self::T_SIEGE, '충차',
@@ -329,19 +329,19 @@ class GameUnitConstBase{
],
[
1502, self::T_SIEGE, '벽력거',
200, 100, 6, 5, 0, 20, 5,
150, 100, 6, 5, 0, 20, 5,
3000, ['업'], null, 0,
[self::T_FOOTMAN=>1.25, self::T_ARCHER=>1.25, self::T_CAVALRY=>1.25, self::T_WIZARD=>1.25, self::T_CASTLE=>1.8, 1106=>1.112],
[self::T_FOOTMAN=>0.833, self::T_ARCHER=>0.833, self::T_CAVALRY=>0.833, self::T_WIZARD=>0.833, 1106=>0.909],
['상대에게 돌덩이를 날립니다.'],
['che_성벽부상무효'], null
['che_성벽부상무효'], ['che_선제사격시도', 'che_선제사격발동']
],
[
1503, self::T_SIEGE, '목우',
50, 200, 5, 0, 0, 15, 5,
3000, ['성도'], null, 0,
[self::T_FOOTMAN=>0.8, self::T_ARCHER=>0.8, self::T_CAVALRY=>0.8, self::T_WIZARD=>0.8],
[self::T_FOOTMAN=>1.2, self::T_ARCHER=>1.2, self::T_CAVALRY=>1.2, self::T_WIZARD=>1.2],
[self::T_FOOTMAN=>1.25, self::T_ARCHER=>1.25, self::T_CAVALRY=>1.25, self::T_WIZARD=>1.25, self::T_CASTLE=>1.8, 1106=>1.112],
[self::T_FOOTMAN=>1, self::T_ARCHER=>1, self::T_CAVALRY=>1, self::T_WIZARD=>1, 1106=>1],
['상대를 저지하는 특수병기입니다.'],
['che_성벽부상무효'], ['che_저지시도', 'che_저지발동']
]
+4 -4
View File
@@ -27,7 +27,7 @@ class GameUnitDetail implements iAction{
public function __construct(
int $id,
int $armType,
string $name,
string $name,
int $attack,
int $defence,
int $speed,
@@ -110,7 +110,7 @@ class GameUnitDetail implements iAction{
}
else if($this->armType == GameUnitConst::T_MISC){
$ratio = $general->getIntel(true, true, true) +
$general->getLeadership(true, true, true) +
$general->getLeadership(true, true, true) +
$general->getStrength(true, true, true);
$ratio = $ratio*2/3 - 40;
}
@@ -174,7 +174,7 @@ class GameUnitDetail implements iAction{
$defaultWar *= 1 + $this->speed / 2;
$defaultWar /= Util::valueFit(1 - $this->avoid / 100, 0.1);
$defaultWar *= 1 + $this->magicCoef / 2;
return sqrt($defaultWar);
return $defaultWar;
}
public function isValid($ownCities, $ownRegions, $relativeYear, $tech){
@@ -256,6 +256,6 @@ class GameUnitDetail implements iAction{
}
}
return new WarUnitTriggerCaller(...$triggerList);
}
}

Some files were not shown because too many files have changed in this diff Show More