Compare commits

...
192 Commits
Author SHA1 Message Date
Hide_D 4f40fa7813 misc: 턴 선택기 버튼 글씨 색 변경 2022-05-13 21:31:49 +09:00
Hide_D b7346b3816 misc: 턴 선택기의 주 버튼 색상 교체 2022-05-13 21:26:22 +09:00
Hide_D 400e47f616 fix: 토너먼트 베팅 시 최소 골드가 500이 아닌 버그 수정 2022-05-13 21:25:30 +09:00
Hide_D 5d499bbfbe fix: 서버 페이지에서 버튼을 bootstrap 버튼으로 변경 2022-05-13 20:27:31 +09:00
Hide_D e0d5c44184 fix: 아이템 버리기시, 조사 틀림 2022-05-13 18:01:31 +09:00
Hide_D f100998800 feat: 게임 시작 후, 거병/건국 기간, 출병 제한 기간을 안내 2022-05-11 02:22:40 +09:00
Hide_D 5bc31c91fa feat: 중원 정세에 메시지를 출력하는 Event Action 추가 2022-05-11 01:58:12 +09:00
Hide_D 4ca929d47d feat: 시작년도 기준으로 연월을 처리하는 Date Condition 추가 2022-05-11 01:50:05 +09:00
Hide_D 4ba43ea76a game: 기병의 출병시 병력 대상 전투력 5% 상향 2022-05-11 01:42:44 +09:00
Hide_D 34232a5504 game: 저지 발동시 숙련에 더해 명성도 추가 2022-05-11 01:36:54 +09:00
Hide_D 9b7464ab69 game: 필살 전투 특기가 '항상 최대 필살 대미지 계수'를 갖도록 수정
- 1.3 ~ 2.0에서 2.0 고정
2022-05-11 01:35:21 +09:00
Hide_D f003f38f74 fix: 일부 자동 조사가 적용되지 않는 코드 반영
- 유산 관리
  - 유니크 이름 받아오는 코드 일부 수정
- 인사부
2022-05-11 00:42:17 +09:00
Hide_D 91b2cecb19 feat: 유니크 입찰 시 첫번째 칸을 '공란'으로 두기 2022-05-11 00:32:03 +09:00
Hide_D 8c11661fb4 fix: 천통시 명장 일람에 유상포인트 최종 계산을 누락한 버그 수정 2022-05-11 00:26:47 +09:00
Hide_D 9aabe0442d game: 이미 같은 부위에 유니크를 가지고 있다면 유산 입찰 금지
- 이미 입찰한 같은 부위 유니크는 반환
2022-05-11 00:12:57 +09:00
Hide_D b463720512 fix: 아이템 파기 시 판매가 정정 2022-05-10 23:59:58 +09:00
Hide_D 6bc7c67589 feat: 장비매매로 유니크 판매시 전체 알림 2022-05-10 23:50:32 +09:00
Hide_D 443543d70f feat: 아이템 파기 추가 2022-05-10 23:46:39 +09:00
Hide_D 46a94b7816 feat: 명장 일람에 유산 소모량, 획득량 표기 2022-05-10 03:31:48 +09:00
Hide_D b2e297bbb3 feat: 유산 포인트 획득, 소모 정도를 동적으로 명장 일람 항목으로 기록
- 1월, 7월
- 베팅, 베팅 당첨을 소모/획득으로 분리
- 일단 유산 포인트 획득은 별도 분리
2022-05-10 03:26:34 +09:00
Hide_D 16906e960e feat: convertTupleArrayToDict 유틸리티 함수 생성 2022-05-10 02:37:50 +09:00
Hide_D 91bc734612 feat: 1, 7월마다 유산 포인트 rank_data 통계를 냄 2022-05-10 01:59:10 +09:00
Hide_D fa5546874a feat: RankColumn 유산 포인트 관련 추가 및 설명 보완 2022-05-09 23:58:15 +09:00
Hide_D 3921d159ef fix: 세력장수에서 rankColumn 대응 에러 수정 2022-05-09 22:33:16 +09:00
Hide_D cfcdc3149f fix: logExceptionByCustomHandler에서 echo 안하는 옵션 추가 2022-05-09 22:31:14 +09:00
Hide_D 717017fad5 misc: APIHelper에서 Exception과 Error를 상세 분리 2022-05-09 22:27:02 +09:00
Hide_D b8f957130d misc: 사용하지 않는 파일 제거 2022-05-09 22:02:54 +09:00
Hide_D 5824079b41 misc: 에러 로깅시 에러명에도 {ROOT}치환 2022-05-09 21:49:02 +09:00
Hide_D fbcfbb7156 fix: KVStorage deleteValue버그 수정 2022-05-09 21:42:17 +09:00
Hide_D b738984235 fix: 토너먼트 함수 인자에 맞게 수정 2022-05-09 21:40:20 +09:00
Hide_D c29333f8e0 fix: RankColumn 누락 부분 수정 2022-05-09 16:12:19 +09:00
Hide_D 123cf8d437 fix: error logger 수정 2022-05-09 16:08:53 +09:00
Hide_D 9293c4e480 feat: FatalError 대응 2022-05-09 03:42:51 +09:00
Hide_D fa5919aa1a Revert "refac: 에러 핸들링 방식 변경, FatalError 대응"
This reverts commit 80edfefdb1.
2022-05-09 03:40:54 +09:00
Hide_D 194f2bd2a5 refac: 에러 핸들링 방식 변경, FatalError 대응 2022-05-09 03:39:30 +09:00
Hide_D 0ae6584b02 fix: 아이템 치료의 우선순위가 낮아 '경상'치료가 안되는 버그 수정 2022-05-09 02:42:08 +09:00
Hide_D 397aa76e15 fix: KVStorage에서 Map으로 안 바뀐 코드 수정 2022-05-09 02:30:11 +09:00
Hide_D 43997b9117 fix: phan 메시지에 따라 수정
- array에 +=를 phan 알아듣기 쉽게 array_merge로
- Util::array_get이 더 이상 필요없으므로 null coalescing
- array로 tuple류를 반환하는 함수에 index를 포함하도록 변경
  - php intelephense에게는 현재 무효
- getPost 일부 값에 int 지정
- 아이템에 id property를 없앴으므로 관련 코드 제거
- enum은 array key로 사용할 수 없으므로 \Ds\Map으로 변경
- KakaoKey PhanRedefineClass 에러 우회
2022-05-09 01:25:12 +09:00
Hide_D de5fe818e6 fix: phan 출력 결과에 따라 처리
- switch에 변수를 정하는 경우 default에 throw
- Util::getPost에 일부 타입 강제
- array인 일부 값들에 PHPDoc 타입 지정
- Enum에 toString이 없으므로 value값 지정
- 사용하지 않는 use function 제거
2022-05-09 00:06:41 +09:00
Hide_D e3e315a068 dep: phan 2022-05-08 23:20:55 +09:00
Hide_D 5430a43589 fix: RankColumn 누락부분 수정 2022-05-08 23:11:15 +09:00
Hide_D a44172f509 refac: RankColumn enum 추가, General의 명장 일람 타입 변경 2022-05-08 23:09:27 +09:00
Hide_D 94bfd79afa fix: 감춰진 KVStorage의 initializer를 사용하는 코드 수정 2022-05-08 20:20:09 +09:00
Hide_D 2b4de68f0a refac: 더는 필요없어진 betting table 삭제 2022-05-08 20:15:03 +09:00
Hide_D 282b413553 refac: InheritPointManager를 Ds\Map으로 변경 2022-05-08 20:11:38 +09:00
Hide_D 5164585360 refac: KVStorage의 내부구조를 Ds\Map으로 변경 2022-05-08 20:10:04 +09:00
Hide_D f6642ecb0f dep: add php-ds 2022-05-08 19:23:24 +09:00
Hide_D 928042d71b feat: KVStorage에서 BackedEnum 지원 2022-05-08 13:30:16 +09:00
Hide_D 91cb3c4344 fix: 오타 수정 2022-05-08 13:15:28 +09:00
Hide_D eff79c4778 refac: 유산 포인트 파트를 별도의 Manager로 분리, enum 적용 2022-05-08 04:40:36 +09:00
Hide_D f7776d5067 dep: bootstrap5 warning 관련 버전 조정 2022-05-08 01:50:19 +09:00
Hide_D 68aae0bec1 misc: warning 제거 2022-05-08 01:44:16 +09:00
Hide_D cb7eb3b711 dep: package-updates 2022-05-08 01:36:06 +09:00
Hide_D 2a6b661285 fix: 연속 내정 성공 등, setInheritancePoint에 빙읮장을 누락한 버그 2022-05-07 15:26:52 +09:00
Hide_D d2ebf94453 fix: 빙의장이 베팅한 경우 베팅 성공으로 반영되지 않는 버그 수정 2022-05-07 15:24:16 +09:00
Hide_D 707f9ba7ce misc: 가입시 닉네임 변경 어려움을 알림 2022-05-07 15:16:38 +09:00
Hide_D 72e1d5e03b fix: 실제 코드 변경에 따라 의술을 1/3가 아니라 30%로 정정 2022-04-28 00:54:34 +09:00
Hide_D a612074aa4 fix: span, br 대신 div 2022-04-27 23:13:51 +09:00
Hide_D 86bbccb7f9 fix: 지도 렌더러에서 tooltip width가 덜 변경되도록 수정 2022-04-27 23:04:22 +09:00
Hide_D 11b7b57343 refac,feat: Global/ExecuteEngine
- 턴 실행
- 기존 proc.php와 유사
- 변경된 턴 있음 알림
2022-04-27 02:43:04 +09:00
Hide_D b682e53abe feat: General|Nation/GetGeneralLog 감찰부&내정보 로그 2022-04-27 01:40:09 +09:00
Hide_D ce877834cd feat: 장수 추가정보 카드
- 막대 구현
- 기존의 추가정보에 5턴분량 예턴 표기
2022-04-27 00:09:25 +09:00
Hide_D c69d171c3a feat: Nation/GeneralList 값 확장, 감찰부 2022-04-27 00:03:33 +09:00
Hide_D 1b24aa2421 feat: 기본 내정보 카드
- 아직 bar가 없음
2022-04-26 03:23:13 +09:00
Hide_D c61a4a70fc feat: Nation/GeneralList에 장수 기본 자료 일부 추가
- 내 정보, 감찰부에서 사용하는 자료
2022-04-26 03:14:48 +09:00
Hide_D bdefcc622f fix: Nation/GeneralList 권한 조정 2022-04-26 03:11:22 +09:00
Hide_D 67336323c2 fix: 세력장수에서 permission1(도시관직)도 보여야함. 2022-04-26 01:02:16 +09:00
Hide_D 3ac9e7c599 misc: 궁병 수비선제사격에서 선제 공격 로그를 단순하게 처리
- 상대방의 필살, 격노도 출력하지 않음
2022-04-26 00:39:36 +09:00
Hide_D 73f70fceff game,fix: 전추 치료 발동시 표기에 맞게 -50% -> -30% 2022-04-26 00:36:30 +09:00
Hide_D e353efc81d game: 궁병 수비 선제의 대미지를 50% 하향 2022-04-26 00:35:08 +09:00
Hide_D a37c427242 misc: auto500px, insertCustomCSS 누락된 페이지 정정 2022-04-26 00:33:54 +09:00
Hide_D d3c9b1f8a6 misc: 불필요한 베팅 import 코드 제거 2022-04-25 21:12:59 +09:00
Hide_D 0ca029babb fix: 천도 후 nationStaticInfo가 갱신되지 않는 버그 수정 2022-04-25 12:00:13 +09:00
Hide_D 492d113307 refac: 토너먼트 긴 switch 문을 assoc array로 변경 2022-04-25 02:33:37 +09:00
Hide_D f2bd48e452 fix,misc: 토너먼트 베팅 관련 잔여 코드 제거 2022-04-25 02:05:59 +09:00
Hide_D ddb7ee1ec2 fix: 국가 베팅장에서 '토너먼트'는 보여주지 않기로 2022-04-25 02:04:31 +09:00
Hide_D 7d62e94306 fix: 금 베팅시 betgold rankvar 누락 2022-04-25 01:51:42 +09:00
Hide_D 4961d76b96 fix: BettingDetail이 assocArray를 대응하지 못하는 버그 수정 2022-04-25 01:45:35 +09:00
Hide_D 12524e6e68 fix: 이제 BettingDetail 출력 변경
- BettingInfo의 candidate가 array를 보장하지 않음
- info가 html이 아니어도 출력
2022-04-25 01:30:54 +09:00
Hide_D 79f30ea275 refac: 토너먼트 베팅 세부 로직을 ng_betting으로 이동 (#218)
- 토너먼트 베팅을 betting 테이블 대신 Betting 모듈을 이용하는 형태로 변경
  - 이전 토너먼트 베팅 기록이 남음
  - 현재 이전 토너먼트 기록을 볼 수는 없음
- 베팅에 API/Betting/Bet 을 이용
- 토너먼트, 베팅 페이지를 Betting 모듈에 맞게 임시 조정
- 이전 버전과의 호환성을 위해 betting table과 betting 테이블에 초기값을 추가하는 로직은 남김
  - 이후 0.30이 되었을 때 제거

Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/218
2022-04-25 01:06:32 +09:00
Hide_D 6ec2bf2880 fix: KVStorage에서 mb_strtolower를 제거하여 대소문자 구분 2022-04-25 00:39:13 +09:00
Hide_D 7708c26b71 refac: Betting 시작 코드를 모듈로 이동 2022-04-23 01:39:02 +09:00
Hide_D 4f300c6f82 refac: 구 jQuery Map wrapper를 Vue3 렌더러로 변경 2022-04-22 02:07:32 +09:00
Hide_D f4d67e759e refac: MapViewer에서 modelValue를 Legacy 버전과 맞춤 2022-04-22 00:36:25 +09:00
Hide_D e9b76217f7 feat: 임시용 cachedMap 출력 추가 2022-04-21 23:51:43 +09:00
Hide_D 85f801df4d feat: MapViewer와 API의 버전이 같을 때에만 지도 출력 2022-04-21 23:51:03 +09:00
Hide_D 01d5f2cda9 fix: 타 버전과 호환성을 위해, NO_SESSION 키워드 유지 2022-04-21 23:37:37 +09:00
Hide_D 601196e3f6 refac: APIHelper에 DummySession 적용, NO_LOGIN 구분 2022-04-21 23:33:08 +09:00
Hide_D cbf0be20a5 feat: SammoAPI 호출 prefix 변경 기능 제공 2022-04-21 23:17:23 +09:00
Hide_D e51421780e fix: 연감 철자 수정 2022-04-21 22:44:02 +09:00
Hide_D 2240282155 fix: 연감에서 폰트 크기 미 지정 2022-04-21 22:32:23 +09:00
Hide_D 5700b32c84 fix: 중원정보에서 분쟁 누락 2022-04-21 22:30:15 +09:00
Hide_D 4d72e0860e fix: AI에서 최근 전투 계산에서 외부 인력 계산 버그 2022-04-21 18:47:38 +09:00
Hide_D 994daf11d3 feat,refac: 중원 정보 페이지 2022-04-21 03:24:11 +09:00
Hide_D 79b92427aa fix: 중원정보 API에서 도시 목록이 id로 나오는 문제 2022-04-21 02:31:41 +09:00
Hide_D 6938c74014 feat: Global/GetDiplomacy 중원 정보 API 2022-04-21 02:28:17 +09:00
Hide_D 058a6e63f2 feat: Global/GetMap, Global/GetCachedMap 추가
-  지도를 가져오는 코드
- GetCahcedMap에서는 600초 단위 캐싱
  - history 필드에 최근 10건 표시
2022-04-21 01:24:07 +09:00
Hide_D 1be6b7a509 misc: Global/GetConst의 캐시 타입을 Public으로 변경 2022-04-21 01:18:12 +09:00
Hide_D ef532f0779 refac: API 캐시 컨트롤에서 max-age, public 지정 가능하도록 2022-04-21 01:17:20 +09:00
Hide_D 095a23df6d fix: get API의 경우 arg를 paramArg로 전환 2022-04-21 00:24:21 +09:00
Hide_D 7043521eaa fix: 연감 지도 수정 2022-04-20 22:40:07 +09:00
Hide_D 5eaafaeee6 fix: NPC 빙의 장수 목록 안보이는 버그 수정
- API/Global/GeneralList를 WithToken과 분리
2022-04-20 22:33:46 +09:00
Hide_D ec10949c64 fix: 걸그룹대전 스탯 수정 2022-04-20 21:56:31 +09:00
Hide_D 0e882cea17 feat: 걸그룹 대전 업데이트 2022-04-20 21:26:55 +09:00
Hide_D 4ad5cab37b feat,refac: vue3로 작성한 새 연감 페이지 (#217)
- 새 지도 렌더러 사용
- 새 연감 데이터 사용
- 500px 모드 지원
- Vue3 활용

Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/217
2022-04-20 21:04:56 +09:00
Hide_D 2b6139050d feat: 커스터마이징 가능한 tooltip directive 2022-04-20 20:58:08 +09:00
Hide_D 14be16ce74 feat: Vue3로 작성된 지도 렌더러 (#216)
- 기존의 jQuery 기반 지도 렌더러를 Vue3로 재작성.
  - ajax로 호출하는 부분은 외부에서 처리하고, 다시 그리는 부분만 생성
  - 기능상으론 거의 동일.
- 일반 렌더러의 700px에, 500px모드용 모드 추가
  - 아이콘의 크기는 작아지지만, 글자 크기는 작아지지 않도록 조정

dep: vueuse, detect-it 추가

Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/216
2022-04-20 03:34:12 +09:00
Hide_D c379ecf317 feat: 연감을 가져오는 API
- Global/GetHistory - 과거 기록. 캐싱 가능
- GetCurrentHistory - 현재 기록. 캐싱 불가
2022-04-18 03:05:08 +09:00
Hide_D eadbc774e3 misc: Global/GetConst session 모드 수정 2022-04-18 00:40:50 +09:00
Hide_D 90787cdc53 fix: 국가베팅 당첨자 없을 시, 버그 2022-04-17 21:40:24 +09:00
Hide_D 337733c3d3 fix,misc: 숙련 등급 입력시 음수인 경우에도 0으로 정상 처리 2022-04-17 21:19:35 +09:00
Hide_D b7048a4422 fix: NPC국 생성 시, 평균 기술력을 받아오지 못하는 문제 수정 2022-04-17 21:17:18 +09:00
Hide_D a036f1c4bb misc: 턴 선택기에서 커맨드 항목 높이를 조절 및 가운데 정렬 2022-04-15 20:11:21 +09:00
sars f9b1ab3ba7 배팅창에서 본선 장수들이 정해져있지 않을때 스탯을 출력하려는 워닝 수정 2022-04-14 19:17:40 -07:00
Hide_D 47599f000a refac: 명장일람, 명예의 전당 2022-04-15 02:36:42 +09:00
Hide_D efb1664443 refac: 감찰부 500px 모드 2022-04-15 02:00:51 +09:00
Hide_D 2c016621b6 game: 군주, 수뇌, 관직 전투력 상향 2022-04-14 01:28:44 +09:00
Hide_D f2a2b338cd fix: 전투 결과가 중복 기록되는 버그 수정 2022-04-13 03:05:23 +09:00
Hide_D 715a66fd35 fix: APIPathGen에서 NumVar, StrVar 동작 오류 2022-04-13 02:49:11 +09:00
Hide_D cc73f8c5d6 game: 베팅 포인트 수령 기준 변경
- 각 단계마다 총 수령액의 1/2씩, 잔여금은 1등상에게로
- 1등이 없는 경우 2등이 1등상+2등상 배분하여 수령
- 4개 선택시 각각, 56.25%, 25%, 12.5%, 6.25%를 나눠가짐
- 정답자가 전혀 없으면 포인트 환불
2022-04-13 02:33:58 +09:00
Hide_D 9b54b2b57d fix: 국가 베팅장에서 화면 이동 시에도 예전 기록이 남는 버그 수정 2022-04-13 02:04:00 +09:00
Hide_D fe4d095f21 game: 수뇌/관직 전투력 보정을 조정
- 수비시, 공격시가 아니라 항시 작동
- 군주: 공격 5%, 피해 -5%
- 참모: 공격 3%, 피해 -3%
- 무장 수뇌: 공격 3%
- 지장 수뇌: 피해 -3%
- 도시 관직: 공격 1.5%, 피해 -1.5%
2022-04-13 01:53:14 +09:00
Hide_D f67fa5c764 misc: JSON.parse 중 any인 것에 type 지정 2022-04-12 22:45:22 +09:00
Hide_D 06249f29cf game: 기병이 돌격 시 궁병 선제에 멈추도록 수정 2022-04-12 22:36:34 +09:00
Hide_D 242efc9ae7 fix: 궁병 수비시 선제로 인해 전투 로그가 두번 출력되는 버그 2022-04-12 22:27:48 +09:00
Hide_D c86572e6f3 game: 궁병에 회피 -5%p 2022-04-12 21:46:57 +09:00
Hide_D 03b458c1b2 game: 궁병에 '선제 사격' 추가
- 공격 시, 상대의 공격력을 1/2로 약화
- 수비 시, '선제 공격' 수행
   - 필살, 계략이 없는 일반 평타 공격
   - 공격자의 총 페이즈는 유지
2022-04-12 21:42:54 +09:00
Hide_D aa2e50366b feat: '선제 페이즈' 도입
- 일종의 '음수' 페이즈
   - 先 표기
   - 수비자 기준
- 내부의 currPhase가 변할 수 있도록 로직 변경
2022-04-12 21:40:49 +09:00
sarsandHide_D 657a47c9ad tournament (#214)
베팅창 QoL 개선

Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/214
Co-authored-by: sars <sarsntony@gmail.com>
Co-committed-by: sars <sarsntony@gmail.com>
2022-04-10 17:46:28 +09:00
Hide_D 5d718bf4ea fix: 약탈발동에 저격특 효과 일부 코드가 남아 있던 버그 수정 2022-04-10 01:52:52 +09:00
Hide_D 082f847b1f game: 과실주(상성)를 대등한 병종에도 발동 2022-04-10 01:17:41 +09:00
Hide_D 54e4d74d0a fix: 장수 생성 페이지 너비 수정 2022-04-08 19:18:51 +09:00
Hide_D 1437d190e5 fix: 세력장수 이름 순에 NPC 정보 반영 2022-04-08 17:21:40 +09:00
Hide_D a95b26551c feat: 통합 세력 장수/암행부 페이지 (#213)
- ag-grid 기반
- 컬럼 사용자 정의 기능 제공
  - 컬럼 재정렬, 고정, 정렬 기능
  - 컬럼 상태 저장, 불러오기
  - 마지막 컬럼 재 사용
- 아이콘, 장수명 클릭 시 특수 기능 제공
  - 기본 세력 장수/암행부에서는 '감찰부'
- 추가 컬럼
  - 최근 전투
  - 전투 수
  - 승리 수
  - 살상률
- API/Nation/GeneralList 추가

Co-authored-by: hide_d <hided62@gmail.com>
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/213
2022-04-08 02:28:58 +09:00
Hide_D c96f6d9381 fix: 초성 오토마타에서 head가 제때 정리되지 않는 버그 2022-04-06 02:41:24 +09:00
Hide_D c7df50d899 fix: vue-tsc 에러 반영 2022-04-05 23:06:58 +09:00
sars 29619ada08 유산 소모에 (필요 포인트가 피보나치식으로 증가합니다) 메세지 추가 2022-04-04 09:51:37 -07:00
Hide_D 222c8a25a4 fix: 최근 실행 턴이 '선택 해제된 턴'을 따르지 않는 버그 수정 2022-04-04 21:40:54 +09:00
sars eac9b7c2e2 오타 수정 (@/SammoAPI에서 ./SammoAPI)로 2022-04-04 00:19:32 -07:00
Hide_D 31d6349d71 fix,refac: ETag 오기록 수정, Cache 설정을 WebUtil로 2022-04-04 01:44:35 +09:00
Hide_D b67f4daf3a refac: 장수 생성페이지 GetConst 활용 2022-04-03 23:14:19 +09:00
Hide_D 81b81d9036 feat: Global/GetConst API의 Store파트 2022-04-03 23:13:31 +09:00
Hide_D 2d06f368f8 refac: APICall에 타입 지정
- 비 undefined 타입에서 ?타입 호출 제거
- API 소속 type들을 defs/API/ 로 이동
- 모든 SammoAPI, SammoRootAPI 지정
2022-04-03 18:16:53 +09:00
Hide_D d0dc0f2bd1 fix: SammoAPICall에서 arg가 지정되어도 undefined가 가능한 버그 2022-04-03 17:15:36 +09:00
Hide_D e301c0fd3e refac: SammoAPI에 타입 지정 2022-04-03 02:17:14 +09:00
Hide_D 5879661267 refac, feat: API 호출 구조 재작성
- api.php에서 param path 강제
- api.php에서 GET param 허용
- SammoAPI 호출자를 axios에서 fetch 기반(ky)로 변경
- SammoAPI에서 단순 POST대신 REST에 따라 지정 가능하도록 재구성
- SammoAPI에서 NumVar, StrVar를 PathParam으로 변경하도록 변경
- API CallType들을 def/API로 분리 시작
  - 일부 API를 시험삼아 변경(login)
2022-04-02 23:31:05 +09:00
Hide_D ad1f070557 feat: 정적 변수를 반환하는 API 추가 Global/GetConst 2022-04-02 18:42:13 +09:00
Hide_D c20986b7b7 misc: BaseNation에서도 getInfo fallback 추가 2022-04-02 18:40:58 +09:00
Hide_D 153f425c99 refac: APIHelper 반환 값 정리 2022-04-02 18:39:47 +09:00
Hide_D 6eb202d4b2 misc: api cache max-age 단축
- 실제 캐시는 etag와 last-modified의 304 반환 활용
- http 2.0을 목표로하므로 큰 문제는 없을 것
2022-04-02 03:12:38 +09:00
Hide_D f7e46e16a3 fix: cache control에서 expires가 남는 문제 수정 2022-04-02 01:17:08 +09:00
Hide_D 36d7e22040 fix: api.php 설정이 전혀 동작하지 않던 문제 수정 2022-04-02 01:14:46 +09:00
Hide_D b24c4806f5 fix: APIHelper에서 tryCache가 잘못된 타입 지정인 버그 2022-04-01 23:27:04 +09:00
Hide_D 8ab79ad9f4 fix: 악질유저무쌍(비급) 시나리오 누락 2022-03-31 19:57:49 +09:00
Hide_D 4f4533e533 refac: linter 관련 설정 변경 및 적용, map_theme 변수 제거
- eslint에 prettier 조합
- prettierrc에 width 120, tabWidth 2
- gameStor->map_theme 제거
- map_theme, mapTheme를 GameConst::$mapName으로 대체
- eslint에서 vue/vue3-essential 대신 vue3-recommended 적용
  - vue/max-attributes-per-line 완화
  - vue/v-on-event-hyphenation 해제
  - vue/attribute-hyphenation 해제
- 일부 tsc import type warning 해결
- 일부 vue template type warning 해결
- 일부 vue SFC를 script setup으로 변경
  - TipTap
  - TopBackBar
  - BottomBackBar
  - BoardArticle
  - ProcessCity
2022-03-29 02:06:47 +09:00
Hide_D e569ffe8f4 build: eslint에서 vue/setup-compiler-macros 활성화
- 필요없어진 import 제거
2022-03-28 22:31:10 +09:00
Hide_D e09709651c fix: 지급률 계산식에서 부대장이 포함되는 버그 수정 2022-03-28 01:15:20 +09:00
Hide_D 39d7b6d55c fix: 1인국 n장 군주일때 발생하는 버그 수정
- 12월, 6월 지급률 계산 시
2022-03-28 01:11:05 +09:00
Hide_D 2b2a328062 game: 계략 성공률 한도를 50%로 제한 2022-03-27 16:55:47 +09:00
Hide_D 65e1495b44 fix: 베팅 대상에 들어가지 않은 국가가 성공 대상인 경우 버그
- purifyBettingKey에서 '해당 국가 없음' 에러를 내지 않도록 변경
2022-03-27 13:11:08 +09:00
Hide_D 3400f5843e game: 도기 판매시 국고와 개인 재산으로 반반씩 2022-03-27 03:54:37 +09:00
Hide_D e580691c1d fix: 백성동원 전략 사용시 국가 열전에 잘못된 양식으로 기록되는 버그 수정 2022-03-27 03:21:55 +09:00
Hide_D bb0e817943 game: 누락된 NPC 비중 수식 반영 2022-03-27 02:49:37 +09:00
Hide_D b7e4db6acd game: 랜임시 유저장 비중 보정
- NPC가 많은 국가가 기존보다 살짝 더 강해짐
- 여전히 유저 위주국가보다 불리
2022-03-27 00:50:03 +09:00
Hide_D 366fe5d613 refac: 시계부분을 분리하여 vue render 최적화 2022-03-27 00:06:40 +09:00
Hide_D 428f2706c3 feat: 최근 실행턴의 중복 관리를 개선 2022-03-26 23:44:01 +09:00
Hide_D 7f2b4596f7 fix: 사령부에서 최근 턴 저장 안되는 버그 수정 2022-03-26 23:30:20 +09:00
Hide_D ab9bdf3822 feat: 사령부의 턴 선택기에 고급 모드 적용 (#212)
- 사령부 턴 페이지를 vue3 setup 형태로 변경
- 턴 조작기 함수 중 공용 함수 분리
- 사령부 턴 조작기 코드 범위를 다시 조정
- 사령부 일반 모드, 고급 모드 이원화
- 사령부에서 다른 수뇌의 턴 '복사하기' 제공

Co-authored-by: Hide_D <hided62@gmail.com>
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/212
Co-authored-by: hide_d <hided62@gmail.com>
Co-committed-by: hide_d <hided62@gmail.com>
2022-03-26 23:11:58 +09:00
Hide_D 585667dfe8 fix: 토너먼트 참가시 한쪽 슬롯이 가득 차면 입장이 닫히는 버그 2022-03-26 17:01:59 +09:00
Hide_D 151e6ed1f3 fix: 세력일람 확장에서 NPC 색상이 고정되는 버그 수정 2022-03-26 02:36:39 +09:00
Hide_D 0685d1caac fix: APIPathGen에서 Var 모드 사용시 에러 2022-03-26 00:04:18 +09:00
Hide_D f50ba83d31 fix: APIPathGen 호출 시 중간 경로 캐싱시 버그 수정 2022-03-25 23:50:41 +09:00
Hide_D 24c043386d refac: SammoAPI Path 정의에 NumVar, StrVar 추가 2022-03-25 23:29:10 +09:00
Hide_D 9d868cb2f4 refac: SammoAPI에서 인자, 반환 타입을 사전 지정 가능 2022-03-25 22:48:34 +09:00
Hide_D be308fdb4a fix: 불가침제의를 원래 의도대로 6개월로 변경 2022-03-24 10:59:04 +09:00
Hide_D 73a5f5287b fix: 중원 정보 표기 에러 수정 시도 2022-03-24 10:37:25 +09:00
Hide_D acafb15215 feat: 여러턴 예약을 ReserveBulkdCommand로 대체 2022-03-24 00:34:05 +09:00
Hide_D 79b9e1b22a fix: 연감 staticValues 중복 2022-03-23 23:51:29 +09:00
Hide_D 7ebdef3116 fix: 연감 표기를 staticValues export에 따라 수정 2022-03-23 23:45:29 +09:00
Hide_D a3fbaa0038 fix: 에러 로그에 따라 수정
- 임관, 하야 등에서 탑승 부대 해제
- 외교 서신 회수시 warning
- DummyGeneral에서 능력치 참조 시.
2022-03-23 23:40:50 +09:00
Hide_D fea2163a01 fix: 세력도시 style 문법 오류 2022-03-23 23:18:00 +09:00
Hide_D d55443968f fix: 세력도시 style 문법 오류 2022-03-23 23:15:11 +09:00
Hide_D b08a2681a2 feat: 세력도시에서 수입 정보 표기, NPC 색 누락분 수정 2022-03-23 23:13:28 +09:00
Hide_D 48af7e5e76 fix: 커맨드 선택시 '간이 복사' 기능이 남아있던 버그 2022-03-23 22:07:59 +09:00
Hide_D 98f48441c9 game: 내정 1% 감소 후, 세율 반영하도록 변경 2022-03-23 20:26:07 +09:00
Hide_D 65f2836379 game: 악질유저무쌍! 시나리오 추가 2022-03-23 20:20:48 +09:00
Hide_D 3548d4e939 feat: 턴 선택기를 재 작성 (#211)
- select form에서 유사 dialog 버튼 방식으로 변경
  - 카테고리마다 페이지 이동
- 일반 모드 / 고급 모드 분리
- 일반 모드에서는 턴별 즉시 설정
- 고급 모드에서는 드래그를 포함한 각종 기능 제공
  - 최근 실행 턴
  - 잘라내기, 복사하기, 붙여넣기
  - 반복하기
  - 비우기
  - 지우고 당기기, 뒤로 밀기
  - 보관하기, 보관한 턴 사용하기

Co-authored-by: Hide_D <hided62@gmail.com>
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/211
Co-authored-by: hide_d <hided62@gmail.com>
Co-committed-by: hide_d <hided62@gmail.com>
2022-03-23 20:13:27 +09:00
Hide_D eb03f34a7e fix: 이미지 안올라가는 버그 수정 2022-03-23 01:01:47 +09:00
Hide_D 40b1a9fbdf build: bootstrap-vue-3
- tiptap/CustomImage 정의 문제 수정
- useToast() 관련 문제 수정
2022-03-20 18:37:38 +09:00
Hide_D 76a31acadc build: tsconfig 변경
- 반영된 룰에 맞게 import type 적용
2022-03-20 12:45:05 +09:00
Hide_D 0f71d786f7 fix: 빙의에서 장수 목록 보기를 사용할 수 없음 2022-03-20 12:14:20 +09:00
sars fec2508091 토너먼트 하이라이트와 토너먼트 액티브를 따로 변수로 저장 2022-03-16 23:10:54 -07:00
383 changed files with 21409 additions and 10403 deletions
+16 -4
View File
@@ -3,20 +3,23 @@ module.exports = {
parser: "vue-eslint-parser",
"env": {
"browser": true,
"es2021": true
"es2021": true,
'vue/setup-compiler-macros': true
},
ignorePatterns: ['*.test.ts', '.eslintrc.cjs', 'postcss.config.cjs', 'webpack.config.cjs', '*.js'],
overrides: [{
files: ['*.ts', '*.tsx', "*.vue"],
}],
plugins: [
"@typescript-eslint"
"@typescript-eslint",
"prettier"
],
extends: [
"eslint:recommended",
"plugin:vue/vue3-essential",
"plugin:@typescript-eslint/recommended"
"plugin:vue/vue3-recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
],
parserOptions: {
"sourceType": "module",
@@ -27,6 +30,15 @@ module.exports = {
},
rules: {
'@typescript-eslint/no-floating-promises': 'error',
'vue/script-setup-uses-vars': 'error',
'vue/max-attributes-per-line': [
'warn',
{
singleline: 4, //prettier와 싸우지 말자
},
],
'vue/v-on-event-hyphenation': 'off', //vue3에선 필요없다고 생각
'vue/attribute-hyphenation': 'off', //vue3에선 필요없다고 생각
},
settings: {
'import/resolver': {
+1 -1
View File
@@ -42,7 +42,7 @@ d_setting/*.php
*/d_setting/templates/*.php
!*.orig.php
*/data/file_cache
**/data/file_cache
**/old/*
test.*
+2 -10
View File
@@ -15,7 +15,8 @@ return [
// Note that the **only** effect of choosing `'5.6'` is to infer
// that functions removed in php 7.0 exist.
// (See `backward_compatibility_checks` for additional options)
"target_php_version" => '8.0',
"target_php_version" => '8.1',
"minimum_target_php_version" => '8.1',
'backward_compatibility_checks ' => true,
'minimum_severity' => \Phan\Issue::SEVERITY_NORMAL,
@@ -39,11 +40,9 @@ return [
'hwe/a_emperior.php',
'hwe/a_genList.php',
'hwe/a_hallOfFame.php',
'hwe/a_history.php',
'hwe/a_kingdomList.php',
'hwe/a_npcList.php',
'hwe/api.php',
'hwe/a_status.php',
'hwe/a_traffic.php',
'hwe/a_vote.php',
'hwe/battle_simulator.php',
@@ -53,7 +52,6 @@ return [
'hwe/v_chiefCenter.php',
'hwe/b_currentCity.php',
'hwe/v_nationStratFinan.php',
'hwe/b_diplomacy.php',
'hwe/b_genList.php',
'hwe/b_myBossInfo.php',
'hwe/b_myCityInfo.php',
@@ -86,7 +84,6 @@ return [
'hwe/j_adjust_icon.php',
'hwe/j_autoreset.php',
'hwe/j_basic_info.php',
'hwe/j_betting.php',
'hwe/j_board_article_add.php',
'hwe/j_board_comment_add.php',
'hwe/j_board_get_articles.php',
@@ -101,15 +98,11 @@ return [
'hwe/j_general_set_permission.php',
'hwe/j_get_basic_general_list.php',
'hwe/j_get_city_list.php',
'hwe/j_get_general_list.php',
'hwe/j_get_nation_general_list.php',
'hwe/j_get_select_npc_token.php',
'hwe/j_get_select_pool.php',
'hwe/j_image_upload.php',
'hwe/j_install_db.php',
'hwe/j_install.php',
'hwe/j_load_scenarios.php',
'hwe/j_map_history.php',
'hwe/j_map.php',
'hwe/j_map_recent.php',
'hwe/j_msg_contact_list.php',
@@ -132,7 +125,6 @@ return [
'hwe/lib.php',
'hwe/process_war.php',
'hwe/proc.php',
'hwe/readme.php',
'hwe/recent_map.php',
'hwe/select_general_from_pool.php',
'hwe/select_npc.php',
+5
View File
@@ -0,0 +1,5 @@
{
"tabWidth": 2,
"useTabs": false,
"printWidth": 120
}
+2 -1
View File
@@ -28,5 +28,6 @@
"cSpell.words": [
"josa",
"sammo"
]
],
"editor.tabSize": 2
}
+5 -1
View File
@@ -8,5 +8,9 @@ require(__DIR__ . '/vendor/autoload.php');
if (!class_exists('\\sammo\\RootDB')) {
Json::dieWithReason('No DB');
}
$eParams = $_GET;
if(key_exists('path', $eParams)){
unset($eParams['path']);
}
APIHelper::launch(dirname(__FILE__), $_GET['path']??null);
APIHelper::launch(dirname(__FILE__), $_GET['path']??'', $eParams, true);
+3 -2
View File
@@ -25,12 +25,13 @@
"ezyang/htmlpurifier": "^4.10",
"xemlock/htmlpurifier-html5": "^0.1.7",
"catfan/medoo": "^1.5",
"phan/phan": "*",
"phan/phan": "^5.3",
"erusev/parsedown-extra": "^0.8.1",
"nette/caching": "^3.0",
"illuminate/database": "^8.61",
"illuminate/events": "^8.61",
"spatie/data-transfer-object": "^3.7"
"spatie/data-transfer-object": "^3.7",
"php-ds/php-ds": "^1.4"
},
"autoload": {
"psr-4": {
Generated
+67 -12
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": "2b7ec5f1a1a908310f3d032f294eacec",
"content-hash": "a32be16440b43a806002e52572e031db",
"packages": [
{
"name": "brandonwamboldt/utilphp",
@@ -1947,21 +1947,21 @@
},
{
"name": "phan/phan",
"version": "5.2.1",
"version": "5.3.2",
"source": {
"type": "git",
"url": "https://github.com/phan/phan.git",
"reference": "d724bbb8fc3ba89179868bb5220ecdf6a9c1636b"
"reference": "b7697eb811e912c038f709f8e1c4911c7ada3edc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phan/phan/zipball/d724bbb8fc3ba89179868bb5220ecdf6a9c1636b",
"reference": "d724bbb8fc3ba89179868bb5220ecdf6a9c1636b",
"url": "https://api.github.com/repos/phan/phan/zipball/b7697eb811e912c038f709f8e1c4911c7ada3edc",
"reference": "b7697eb811e912c038f709f8e1c4911c7ada3edc",
"shasum": ""
},
"require": {
"composer/semver": "^1.4|^2.0|^3.0",
"composer/xdebug-handler": "^1.3.2|^2.0.0",
"composer/xdebug-handler": "^2.0|^3.0",
"ext-filter": "*",
"ext-json": "*",
"ext-tokenizer": "*",
@@ -1969,8 +1969,8 @@
"microsoft/tolerant-php-parser": "^0.1.0",
"netresearch/jsonmapper": "^1.6.0|^2.0|^3.0|^4.0",
"php": "^7.2.0|^8.0.0",
"sabre/event": "^5.0.3",
"symfony/console": "^3.2|^4.0|^5.0",
"sabre/event": "^5.1.3",
"symfony/console": "^3.2|^4.0|^5.0|^6.0",
"symfony/polyfill-mbstring": "^1.11.0",
"symfony/polyfill-php80": "^1.20.0",
"tysonandre/var_representation_polyfill": "^0.0.2|^0.1.0"
@@ -1979,7 +1979,7 @@
"phpunit/phpunit": "^8.5.0"
},
"suggest": {
"ext-ast": "Needed for parsing ASTs (unless --use-fallback-parser is used). 1.0.1+ is needed, 1.0.14+ is recommended.",
"ext-ast": "Needed for parsing ASTs (unless --use-fallback-parser is used). 1.0.1+ is needed, 1.0.16+ is recommended.",
"ext-iconv": "Either iconv or mbstring is needed to ensure issue messages are valid utf-8",
"ext-igbinary": "Improves performance of polyfill when ext-ast is unavailable",
"ext-mbstring": "Either iconv or mbstring is needed to ensure issue messages are valid utf-8",
@@ -2020,9 +2020,64 @@
],
"support": {
"issues": "https://github.com/phan/phan/issues",
"source": "https://github.com/phan/phan/tree/5.2.1"
"source": "https://github.com/phan/phan/tree/5.3.2"
},
"time": "2021-09-15T00:08:40+00:00"
"time": "2022-02-01T00:17:36+00:00"
},
{
"name": "php-ds/php-ds",
"version": "v1.4.1",
"source": {
"type": "git",
"url": "https://github.com/php-ds/polyfill.git",
"reference": "43d2df301a9e2017f67b8c11d94a5222f9c00fd1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-ds/polyfill/zipball/43d2df301a9e2017f67b8c11d94a5222f9c00fd1",
"reference": "43d2df301a9e2017f67b8c11d94a5222f9c00fd1",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": ">=7.0"
},
"provide": {
"ext-ds": "1.3.0"
},
"require-dev": {
"php-ds/tests": "^1.3"
},
"suggest": {
"ext-ds": "to improve performance and reduce memory usage"
},
"type": "library",
"autoload": {
"psr-4": {
"Ds\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rudi Theunissen",
"email": "rudolf.theunissen@gmail.com"
}
],
"keywords": [
"data structures",
"ds",
"php",
"polyfill"
],
"support": {
"issues": "https://github.com/php-ds/polyfill/issues",
"source": "https://github.com/php-ds/polyfill/tree/v1.4.1"
},
"time": "2022-03-09T20:39:30+00:00"
},
{
"name": "php-extended/php-system",
@@ -6036,5 +6091,5 @@
"platform-overrides": {
"php": "8.0"
},
"plugin-api-version": "2.0.0"
"plugin-api-version": "2.2.0"
}
+7 -2
View File
@@ -36,16 +36,21 @@ body {
height: 130px;
}
#user_info button {
#user_info .btn {
width: 200px;
height: 50px;
margin: 10px 50px;
padding: 10px;
}
.center_ordered_items {
text-align: center;
}
.server-action{
padding-top: 16px;
padding-bottom: 16px;
}
.Entrance_ServerList {
width: 800px;
height: 64px;
+34 -16
View File
@@ -49,7 +49,7 @@ function getFriendlyErrorType($type)
return "{$type}";
}
function getExceptionTraceAsString($exception)
function getExceptionTraceAsString(\Throwable $exception)
{
//https://gist.github.com/abtris/1437966
$rtn = "";
@@ -96,6 +96,7 @@ function logError(string $err, string $errstr, string $errpath, array $trace)
$fdb = FileDB::db(ROOT . '/d_log/err_log.sqlite3', ROOT . '/f_install/sql/err_log.sql');
$date = date("Ymd_His");
$err =str_replace(ROOT, '{ROOT}', $errpath);
$errpath = str_replace(ROOT, '{ROOT}', $errpath);
$trace = array_map(function (string $text) {
return str_replace(ROOT, '{ROOT}', $text);
@@ -117,7 +118,7 @@ function logError(string $err, string $errstr, string $errpath, array $trace)
]);
}
function logErrorByCustomHandler(int $errno, string $errstr, string $errfile, int $errline, array $errcontext=null)
function logErrorByCustomHandler(int $errno, string $errstr, string $errfile, int $errline)
{
if (!(error_reporting() & $errno)) {
// This error code is not included in error_reporting, so let it fall
@@ -133,11 +134,12 @@ function logErrorByCustomHandler(int $errno, string $errstr, string $errfile, in
$errfile . ':' . $errline,
getExceptionTraceAsString($e)
);
return true;
}
set_error_handler("\\sammo\\logErrorByCustomHandler");
function logExceptionByCustomHandler(\Throwable $e)
function logExceptionByCustomHandler(\Throwable $e, bool $withDie = true)
{
logError(
@@ -147,32 +149,48 @@ function logExceptionByCustomHandler(\Throwable $e)
getExceptionTraceAsString($e)
);
echo $e->getTraceAsString();
throw $e;
if($withDie){
echo $e->getTraceAsString();
throw $e;
}
}
set_exception_handler('\\sammo\\logExceptionByCustomHandler');
function getAPIExecutorClass($path){
function checkForFatal()
{
$error = error_get_last();
if($error === null){
return;
}
if (($error["type"]??0) == E_ERROR) {
logErrorByCustomHandler($error["type"], $error["message"], $error["file"], $error["line"]);
}
}
static $basePath = __NAMESPACE__.'\\API\\';
if(is_string($path)){
}
else if(is_array($path)){
register_shutdown_function("\\sammo\\checkForFatal");
function getAPIExecutorClass($path)
{
static $basePath = __NAMESPACE__ . '\\API\\';
if (is_string($path)) {
} else if (is_array($path)) {
$path = join('\\', $path);
}
else{
} else {
throw new \InvalidArgumentException("{$path}는 올바른 API 지시자가 아님");
}
$classPath = str_replace('/', '\\', $basePath.$path);
$classPath = str_replace('/', '\\', $basePath . $path);
if(class_exists($classPath)){
if (class_exists($classPath)) {
return $classPath;
}
throw new \InvalidArgumentException("{$path}는 올바른 API 경로가 아님");
}
function buildAPIExecutorClass($type, string $rootPath, array $args):\sammo\BaseAPI{
function buildAPIExecutorClass($type, string $rootPath, array $args): \sammo\BaseAPI
{
$class = getAPIExecutorClass($type);
return new $class($rootPath, $args);
}
}
+1 -1
View File
@@ -14,7 +14,7 @@ $gameStor = KVStorage::getStorage($db, 'game_env');
[$turntime, $tnmt_time] = $gameStor->getValuesAsArray(['turntime','tnmt_time']);
$plock = $db->queryFirstField('SELECT plock FROM plock');
$plock = $db->queryFirstField('SELECT plock FROM plock WHERE `type` ="GAME"');
?>
<!DOCTYPE html>
<html>
+1
View File
@@ -72,6 +72,7 @@ switch ($btn) {
case "30분턴": $turnterm = 30; break;
case "60분턴": $turnterm = 60; break;
case "120분턴": $turnterm = 120; break;
default: throw new \Exception("알 수 없는 턴 기간");
}
$oldunit = $admin['turnterm'] * 60;
$unit = $turnterm * 60;
+2
View File
@@ -5,7 +5,9 @@ namespace sammo;
include "lib.php";
include "func.php";
/** @var int */
$type = Util::getPost('type', 'int', 0);
/** @var int */
$type2 = Util::getPost('type2', 'int', 0);
if ($type < 0 || $type > 17) {
+2
View File
@@ -95,6 +95,8 @@ $sel[$type] = "selected";
case 7:
$state = "<font color=green>불가침</font>";
break;
default:
throw new \Exception("알 수 없는 외교 상태: {$dip['state']}");
}
$date = TimeUtil::now();
+4 -3
View File
@@ -25,8 +25,9 @@ foreach ($db->queryFirstColumn(
CheckHall($generalNo);
}
$inheritPointManager = InheritancePointManager::getInstance();
foreach(General::createGeneralObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc = 0')) as $genObj){
$genObj->mergeTotalInheritancePoint(true);
applyInheritanceUser($genObj->getVar('owner'));
$genObj->clearInheritancePoint();
$inheritPointManager->mergeTotalInheritancePoint($genObj, true);
$inheritPointManager->applyInheritanceUser($genObj->getVar('owner'));
$inheritPointManager->clearInheritancePoint($genObj);
}
+46 -30
View File
@@ -2,6 +2,8 @@
namespace sammo;
use sammo\Enums\RankColumn;
include "lib.php";
include "func.php";
@@ -24,32 +26,26 @@ $templates = new \League\Plates\Engine(__DIR__ . '/templates');
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1136" />
<meta name="viewport" content="width=500" />
<title><?= UniqueConst::$serverName ?>: 명장일람</title>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printCSS('css/hallOfFame.css') ?>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printDist('ts', 'common') ?>
<?= WebUtil::printDist('ts', ['common', 'bestGeneral']) ?>
</head>
<body>
<table align=center width=1100 class='tb_layout bg0'>
<tr>
<td>명 장 일 람<br><?= closeButton() ?></td>
</tr>
</table>
<table align=center width=1100 class='tb_layout bg0'>
<form name=form1 action=a_bestGeneral.php method=post>
<tr>
<td align=center>
<input type=submit name=btn value='유저 보기'>
<div id="container" class="bg0">
<div class="row gx-0">
<div class="col">명 장 일 람<br><?= closeButton() ?></div>
</div>
<div class="row gx-0">
<div class="col center">
<form name=form1 action=a_bestGeneral.php method=get><input type=submit name=btn value='유저 보기'>
<input type=submit name=btn value='NPC 보기'>
</td>
</tr>
</form>
</table>
<div style="margin:auto;width:1100px;">
</form>
</div>
</div>
<?php
$ownerNameList = [];
@@ -209,6 +205,32 @@ $templates = new \League\Plates\Engine(__DIR__ . '/templates');
}
return $v;
}],
["유 산 소 모 량", "int", function ($v) use ($gameStor) {
$v['value'] = $v[RankColumn::inherit_point_spent->value];
if ($gameStor->isunited) {
return $v;
}
$v['nationName'] = '???';
$v['pictureFullPath'] = GetImageURL(0) . "/default.jpg";
$v['name'] = '???';
$v['ownerName'] = null;
$v['bgColor'] = GameConst::$basecolor4;
$v['fgColor'] = newColor($v['bgColor']);
return $v;
}],
["유 산 획 득 량", "int", function ($v) use ($gameStor) {
$v['value'] = $v[RankColumn::inherit_point_earned->value];
if ($gameStor->isunited) {
return $v;
}
$v['nationName'] = '???';
$v['pictureFullPath'] = GetImageURL(0) . "/default.jpg";
$v['name'] = '???';
$v['ownerName'] = null;
$v['bgColor'] = GameConst::$basecolor4;
$v['fgColor'] = newColor($v['bgColor']);
return $v;
}],
];
$generals = [];
@@ -274,10 +296,6 @@ $templates = new \League\Plates\Engine(__DIR__ . '/templates');
'generals' => array_slice($typeGenerals, 0, min(10, $validCnt))
]);
}
?>
</div>
<div style="margin:auto;width:1100px;margin-top:5px;">
<?php
//유니크 아이템 소유자
$itemTypes = [
'horse' => '명 마',
@@ -369,15 +387,13 @@ $templates = new \League\Plates\Engine(__DIR__ . '/templates');
]);
}
?>
<div class="row gx-0">
<div class="col"><?= closeButton() ?></div>
</div>
<div class="row bg0 gx-0">
<div class="col bg0"><?= banner() ?></div>
</div>
</div>
<table align=center width=1100 class='tb_layout bg0'>
<tr>
<td><?= closeButton() ?></td>
</tr>
<tr>
<td><?= banner() ?> </td>
</tr>
</table>
</body>
</html>
+2 -2
View File
@@ -55,7 +55,7 @@ increaseRefresh("왕조일람", 1);
<tr>
<td style="background-color:#333333;" align=center colspan=8>
<font size=5>현재 (<?= $year ?>年 <?= $month ?>月)</font>
<a href="a_history.php"><button type='button'>역사 보기</button></a>
<a href="v_history.php"><button type='button'>역사 보기</button></a>
</td>
</tr>
</table>
@@ -75,7 +75,7 @@ increaseRefresh("왕조일람", 1);
<a href="a_emperior_detail.php?select=<?= $emperior['no'] ?>"><button type='button'>자세히</button></a>
<?php if ($emperior['server_id']) : ?>
<a href="a_history.php?serverID=<?= $emperior['server_id'] ?>"><button type='button'>역사 보기</button></a>
<a href="v_history.php?serverID=<?= $emperior['server_id'] ?>"><button type='button'>역사 보기</button></a>
<?php endif ?>
</td>
</tr>
+3 -2
View File
@@ -173,8 +173,9 @@ $serverID = $emperior['server_id'] ?? ($emperior['serverID'] ?? null);
if (!$nation['nation'] ?? null) {
continue;
}
$nation += Json::decode($nation['data']);
$nation = array_merge(Json::decode($nation['data']), $nation);
/** @var array $nation */
$nation['typeName'] = getNationType($nation['type']);
$nation['levelName'] = getNationLevel($nation['level']);
/** @var int[]|null $nationGenerals */
@@ -200,7 +201,7 @@ $serverID = $emperior['server_id'] ?? ($emperior['serverID'] ?? null);
}
if (key_exists('aux', $nation) && !is_array($nation['aux'])) {
$nation += Json::decode($nation['aux']);
$nation = array_merge(Json::decode($nation['aux']), $nation);
}
echo $templates->render('oldNation', $nation);
+1
View File
@@ -172,6 +172,7 @@ if ($gameStor->isunited) {
data-general-strength='{$general['strength']}'
data-general-intel='{$general['intel']}'
data-is-npc='" . ($general['npc'] >= 2 ? 'true' : 'false') . "'
data-npc-type='{$general['npc']}'
>
<td align=center><img class='generalIcon' width='64' height='64' src='{$imageTemp}/{$general['picture']}'></img></td>
<td align=center>$name</td>
+20 -23
View File
@@ -44,22 +44,21 @@ if ($scenarioIdx && key_exists($scenarioIdx, $scenarioList[$seasonIdx] ?? [])) {
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1136" />
<meta name="viewport" content="width=500" />
<title><?= UniqueConst::$serverName ?>: 명예의 전당</title>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printCSS('css/hallOfFame.css') ?>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printDist('ts', ['common', 'hallOfFame']) ?>
</head>
<body>
<table align=center width=1100 class='tb_layout bg0'>
<tr>
<td>명 예 의 전 당<br><?= closeButton() ?></td>
</tr>
<tr>
<td>
<div id="container" class="bg0">
<div class="row gx-0">
<div class="col">명 예 의 전 당<br><?= closeButton() ?></div>
</div>
<div class="row gx-0">
<div class="col center">
시나리오 검색 : <select id="by_scenario" name="by_scenario">
<?php foreach ($scenarioList as $iterSeasonIdx => $subScenarioList) : ?>
<option data-season="<?= $iterSeasonIdx ?>" value="" <?= ($iterSeasonIdx == $seasonIdx && $scenarioIdx === null) ? "selected='selected'" : '' ?>>* 시즌 : <?= $iterSeasonIdx ?> 종합 *</option>
@@ -69,10 +68,8 @@ if ($scenarioIdx && key_exists($scenarioIdx, $scenarioList[$seasonIdx] ?? [])) {
<?php endforeach; ?>
?>
</select>
</td>
</tr>
</table>
<div style="margin:auto;width:1100px;">
</div>
</div>
<?php
$types = [
'experience' => ['명 성', 'int'],
@@ -113,7 +110,8 @@ if ($scenarioIdx && key_exists($scenarioIdx, $scenarioList[$seasonIdx] ?? [])) {
$hallResult = array_map(function ($general) use ($typeValue, $ownerNameList) {
$aux = Json::decode($general['aux']);
$general += $aux;
/** @var array $general */
$general = array_merge($aux, $general);
if (key_exists($general['owner'], $ownerNameList)) {
$general['ownerName'] = $ownerNameList[$general['owner']];
@@ -121,10 +119,11 @@ if ($scenarioIdx && key_exists($scenarioIdx, $scenarioList[$seasonIdx] ?? [])) {
if (!key_exists('bgColor', $general)) {
if (!key_exists('color', $general)) {
$general['bgColor'] = GameConst::$basecolor4;
$color = GameConst::$basecolor4;
} else {
$general['bgColor'] = $general['color'];
$color = $general['color'];
}
$general['bgColor'] = $color;
}
if (!key_exists('fgColor', $general)) {
@@ -156,15 +155,13 @@ if ($scenarioIdx && key_exists($scenarioIdx, $scenarioList[$seasonIdx] ?? [])) {
]);
}
?>
<div class="row gx-0">
<div class="col"><?= closeButton() ?></div>
</div>
<div class="row bg0 gx-0">
<div class="col bg0"><?= banner() ?></div>
</div>
</div>
<table align=center width=1100 class='tb_layout bg0'>
<tr>
<td><?= closeButton() ?></td>
</tr>
<tr>
<td><?= banner() ?> </td>
</tr>
</table>
</body>
</html>
-229
View File
@@ -1,229 +0,0 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
$btn = Util::getReq('btn');
$yearMonth = Util::getReq('yearmonth', 'int');
$serverID = Util::getReq('serverID', 'string', null);
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
if (!$serverID) {
$serverID = UniqueConst::$serverID;
}
if ($serverID === UniqueConst::$serverID) {
increaseRefresh("연감", 1);
}
$admin = $gameStor->getValues(['startyear', 'year', 'month', 'map_theme']);
$me = $db->queryFirstRow('SELECT con, turntime FROM general WHERE owner = %i', $userID);
$con = checkLimit($me['con']);
if ($con >= 2) {
printLimitMsg($me['turntime']);
exit();
}
[$s_year, $s_month] = $db->queryFirstList('SELECT year, month FROM ng_history WHERE server_id = %s ORDER BY year ASC, month ASC LIMIT 1', $serverID);
$s = Util::joinYearMonth($s_year, $s_month);
if ($s_year === null) {
echo '인자 에러';
exit();
}
[$e_year, $e_month] = $db->queryFirstList('SELECT year, month FROM ng_history WHERE server_id = %s ORDER BY year DESC, month DESC LIMIT 1', $serverID);
$e = Util::joinYearMonth($e_year, $e_month);
if ($serverID !== UniqueConst::$serverID) {
$mapTheme = $db->queryFirstField('SELECT map FROM ng_games WHERE server_id=%s', $serverID) ?: 'che';
} else {
$mapTheme = $admin['map_theme'] ?? 'che';
}
//FIXME: $yearmonth가 올바르지 않을 경우에 처리가 필요.
if ($serverID !== UniqueConst::$serverID && !$yearMonth) {
$yearMonth = $s;
} else if (!$yearMonth) {
$yearMonth = Util::joinYearMonth($admin['year'], $admin['month']);
} else {
if ($btn == "◀◀ 이전달") {
$yearMonth -= 1;
} elseif ($btn == "다음달 ▶▶") {
$yearMonth += 1;
}
}
$isCurrent = false;
if ($yearMonth < $s) {
$yearMonth = $s;
}
if ($yearMonth > $e) {
$isCurrent = true;
$yearMonth = $e + 1;
}
[$year, $month] = Util::parseYearMonth($yearMonth);
function getHistory($serverID, $year, $month):array{
$db = DB::db();
$history = $db->queryFirstRow('SELECT * FROM ng_history WHERE server_id = %s AND year = %i AND month = %i', $serverID, $year, $month);
$history['global_history'] = Json::decode($history['global_history']);
$history['global_action'] = Json::decode($history['global_action']);
$history['nations'] = Json::decode($history['nations']);
return $history;
}
if($isCurrent){
$history = getCurrentHistory();
}
else{
$history = getHistory($serverID, $year, $month);
}
$nations = $history['nations'];
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 연감</title>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printJS("js/map/theme_{$mapTheme}.js") ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<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::printCSS('css/history.css') ?>
<?= WebUtil::printDist('ts', ['common', 'history']) ?>
<script>
var startYear = <?= $s_year ?>;
var startMonth = <?= $s_month ?>;
var lastYear = <?= $e_year ?>;
var lastMonth = <?= $e_month ?>;
var selectYear = <?= $year ?>;
var selectMonth = <?= $month ?>;
var nations = <?= $nations ? JSON::encode($history['nations']) : '{}' ?>;
</script>
</head>
<body>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td>연 감<br><?= closeButton() ?></td>
</tr>
<tr>
<td>
<form name=form1 method=post>
연월 선택 :
<input type=submit name=btn value="◀◀ 이전달">
<select id='yearmonth' name=yearmonth size=1>
<option selected='selected'><?= $year ?>년 <?= $month ?>월</option>
<option><?= $e_year ?>년 12월 (현재)</option>
</select>
<input type=submit name=btn value='조회하기'>
<input type=submit name=btn value="다음달 ▶▶">
</form>
</td>
</tr>
</table>
<table align=center width=1000 height=520 class='tb_layout bg0'>
<thead>
<tr>
<th colspan=5 align=center class='bg1'>중 원 지 도</th>
</tr>
</thead>
<tbody>
<tr height=520>
<td width=698>
<?= getMapHtml($mapTheme) ?>
</td>
<td id='nation_list_frame'>
<table id='nation_list'>
<thead>
<tr>
<th width=130>국명</th>
<th width=70>국력</th>
<th width=45>장수</th>
<th width=45>속령</th>
</tr>
</thead>
<tbody>
<?php foreach ($nations as $nation) : ?>
<tr>
<td><span style='color:<?= newColor($nation['color']) ?>;background-color:<?= $nation['color'] ?>'><?= $nation['name'] ?></td>
<td style='text-align:right'><?= number_format($nation['power']) ?></td>
<td style='text-align:right'><?= number_format($nation['gennum']) ?></td>
<td style='text-align:right'><?= number_format(count($nation['cities'] ?? [])) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot></tfoot>
</table>
</td>
</tr>
<tr>
<th colspan=5 align=center class='bg1'>중 원 정 세</th>
</tr>
<tr>
<td colspan=5 valign=top>
<?= formatHistoryToHTML($history['global_history']) ?>
</td>
</tr>
<tr>
<th colspan=5 align=center class='bg1'>장 수 동 향</th>
</tr>
<tr>
<td colspan=5 valign=top>
<?= formatHistoryToHTML($history['global_action']) ?>
</td>
</tr>
</tbody>
</table>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td><?= closeButton() ?></td>
</tr>
<tr>
<td><?= banner() ?> </td>
</tr>
</table>
<script>
window.serverNick = '<?= DB::prefix() ?>';
window.serverID = '<?= UniqueConst::$serverID ?>';
<?php if($isCurrent): ?>
reloadWorldMap({
showMe: false,
neutralView: true,
useCachedMap: true,
});
<?php else: ?>
reloadWorldMap({
targetJson: 'j_map_history.php?year=<?= $year ?>&month=<?= $month ?>&serverID=<?= $serverID ?>',
showMe: false,
neutralView: true,
useCachedMap: false,
year: <?= $year ?>,
month: <?= $month ?>,
});
<?php endif; ?>
</script>
</body>
</html>
+2 -2
View File
@@ -111,7 +111,7 @@ if ($con >= 2) {
}
$chief = $chiefs[$chiefLevel] ?? ['name' => '-', 'npc' => 0];
$officerLevelText = getOfficerLevelText($chiefLevel, $nation['level']);
$chiefText = getColoredName($chief['name'], $chief['npc']);
$chiefText = formatName($chief['name'], $chief['npc']);
echo "<td class='center bg1'>{$officerLevelText}</td>
<td class='center'>{$chiefText}</td>";
}
@@ -178,7 +178,7 @@ if ($con >= 2) {
<tr>
<td colspan=5> 장수 일람 : ";
foreach ($nations[0]['generals'] as $general) {
$generalText = getColoredName($general['name'], $general['npc']);
$generalText = formatName($general['name'], $general['npc']);
echo "{$generalText}, ";
}
echo "
+1 -1
View File
@@ -111,7 +111,7 @@ $sel[$type] = "selected";
</tr>
<?php foreach ($generalList as $general) : ?>
<tr>
<td align=center><?= getColoredName($general['name'], $general['npc']) ?></td>
<td align=center><?= formatName($general['name'], $general['npc']) ?></td>
<td align=center><?= $general['owner_name'] ?></td>
<td align=center>Lv <?= $general['explevel'] ?></td>
<td align=center><?= $nationName[$general['nation']] ?></td>
+6 -1
View File
@@ -5,4 +5,9 @@ namespace sammo;
include "lib.php";
include "func.php";
APIHelper::launch(dirname(__FILE__), $_GET['path']??null);
$eParams = $_GET;
if(key_exists('path', $eParams)){
unset($eParams['path']);
}
APIHelper::launch(dirname(__FILE__), $_GET['path']??'', $eParams, true);
+67 -76
View File
@@ -74,7 +74,7 @@ if ($testGeneralNationID != $nationID) {
$gen = 0;
}
if ($btn == '정렬하기') {
if ($btn == '정렬') {
$gen = 0;
}
@@ -118,100 +118,91 @@ $showGeneral = General::createGeneralObjFromDB($gen);
<title><?= UniqueConst::$serverName ?>: 감찰부</title>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<meta name="viewport" content="width=500" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printDist('ts', ['common']) ?>
<?= WebUtil::printDist('ts', ['common', 'battleCenter']) ?>
</head>
<body>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td>감 찰 부<br><?= closeButton() ?></td>
</tr>
<tr>
<td>
<form name=form1 method=post>
<div id="container" class="bg0">
<div class="row gx-0">
<div class="col">감 찰 부<br><?= closeButton() ?></div>
</div>
<div class="row gx-0">
<div class="col-12" style="border-left: solid 1px gray; border-right:solid 1px gray;">
<form name=form1 method=get>
정렬순서 :
<select name='query_type' size=1>
<?php foreach ($queryMap as $queryType => [$queryTypeText,]) : ?>
<option <?= $queryType == $reqQueryType ? 'selected' : '' ?> value='<?= $queryType ?>'><?= $queryTypeText ?></option>
<?php endforeach; ?>
</select>
<input type=submit name=btn value='정렬하기'>
<input type=submit name=btn value='정렬'>
대상장수 :
<select name=gen size=1>
<?php foreach ($generalBasicList as $general) : ?>
<option <?= $gen == $general['no'] ? 'selected' : '' ?> value='<?= $general['no'] ?>'><?= $general['officer_level'] > 4 ? "*{$general['name']}*" : $general['name'] ?> (<?= substr($general['turntime'], 14, 5) ?>)</option>
<?php endforeach; ?>
</select>
<input type=submit name=btn value='조회하기'>
<input type=submit name=btn value='조회'>
</form>
</td>
</tr>
</table>
<table width=1000 align=center class='tb_layout bg0'>
<tr>
<td width=50% align=center class='bg1'>
<font color=skyblue size=3>장 수 정 보</font>
</td>
<td width=50% align=center class='bg1'>
<font color=orange size=3>장 수 열 전</font>
</td>
</tr>
<tr>
<td valign=top>
<?php generalInfo($showGeneral);
generalInfo2($showGeneral); ?>
</td>
<td valign=top>
<?= formatHistoryToHTML(getGeneralHistoryLogAll($gen)) ?>
</td>
</tr>
<tr>
<td align=center class='bg1'>
<font color=orange size=3>전투 기록</font>
</td>
<td align=center class='bg1'>
<font color=orange size=3>전투 결과</font>
</td>
</tr>
<tr>
<td valign=top>
<?= formatHistoryToHTML(getBattleDetailLogRecent($gen, 24)) ?>
</td>
<td valign=top>
<?= formatHistoryToHTML(getBattleResultRecent($gen, 24)) ?>
</td>
</tr>
<?php if ($showGeneral->getNPCType() > 1 || $permission >= 2) : ?>
<tr>
<td align=center class='bg1'>
<font color=orange size=3>개인 기록</font>
</td>
<td align=center class='bg1'>
<font color=orange size=3>&nbsp;</font>
</td>
</tr>
<tr>
<td valign=top>
<?= formatHistoryToHTML(getGeneralActionLogRecent($gen, 24)) ?>
</td>
<td valign=top>
</td>
</tr>
<?php endif; ?>
</table>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td><?= closeButton() ?></td>
</tr>
<tr>
<td><?= banner() ?> </td>
</tr>
</table>
</div>
<div class="col col-12 col-md-6">
<div class="row mx-0">
<div class="col bg1 header-cell" style="color:skyblue">장수 정보</div>
</div>
<div class="row">
<div class="col"><?php generalInfo($showGeneral); ?><?php generalInfo2($showGeneral); ?></div>
</div>
</div>
<div class="col col-12 col-md-6">
<div class="row mx-0">
<div class="col bg1 header-cell">장수 열전</div>
</div>
<div class="row">
<div class="col"><?= formatHistoryToHTML(getGeneralHistoryLogAll($gen)) ?></div>
</div>
</div>
<div class="col col-12 col-md-6">
<div class="row mx-0">
<div class="col bg1 header-cell">전투 기록</div>
</div>
<div class="row">
<div class="col"><?= formatHistoryToHTML(getBattleDetailLogRecent($gen, 24)) ?></div>
</div>
</div>
<div class="col col-12 col-md-6">
<div class="row mx-0">
<div class="col bg1 header-cell">전투 결과</div>
</div>
<div class="row">
<div class="col"><?= formatHistoryToHTML(getBattleResultRecent($gen, 24)) ?></div>
</div>
</div>
<?php if ($showGeneral->getNPCType() > 1 || $permission >= 2) : ?>
<div class="col col-12 col-md-6">
<div class="row mx-0">
<div class="col bg1 header-cell">개인 기록</div>
</div>
<div class="row">
<div class="col"><?= formatHistoryToHTML(getGeneralActionLogRecent($gen, 24)) ?></div>
</div>
</div>
<?php endif; ?>
</div>
<div class="row gx-0">
<div class="col "><?= backButton() ?></div>
</div>
<div class="row bg0 gx-0">
<div class="col bg0"><?= banner() ?></div>
</div>
</div>
</body>
</html>
+111 -65
View File
@@ -2,6 +2,8 @@
namespace sammo;
use sammo\Enums\RankColumn;
include "lib.php";
include "func.php";
//로그인 검사
@@ -16,17 +18,11 @@ TurnExecutionHelper::executeAllCommand();
$generalID = $session->generalID;
//NOTE: general_id만 빼기 귀찮음.
$myBet = $db->queryFirstList('SELECT * FROM betting WHERE general_id = %i', $generalID);
$myBet = array_splice($myBet, -16);
$globalBet = $db->queryFirstList('SELECT * FROM betting WHERE general_id = 0');
$globalBet = array_splice($globalBet, -16);
$me = $db->queryFirstRow('SELECT no,tournament,con,turntime from general where owner=%i', $userID);
$myBetTotal = array_sum($myBet);
$globalBetTotal = array_sum($globalBet);
$admin = $gameStor->getValues(['tournament', 'phase', 'tnmt_type', 'develcost']);
$con = checkLimit($me['con']);
@@ -36,34 +32,68 @@ if ($con >= 2) {
}
switch ($admin['tnmt_type']) {
default:
throw new \RuntimeException('Invalid tnmt_type');
case 0:
$tnmt_type = "<font color=cyan>전력전</font>";
case convertTournamentType('전력전'):
$tnmt_type = "전력전";
$color = "cyan";
$tp = "total";
$tp2 = "종합";
$tp3 = "total";
break;
case 1:
$tnmt_type = "<font color=cyan>통솔전</font>";
case convertTournamentType('통솔전'):
$tnmt_type = "통솔전";
$color = "cyan";
$tp = "leadership";
$tp2 = "통솔";
$tp3 = "leadership";
break;
case 2:
$tnmt_type = "<font color=cyan>일기토</font>";
case convertTournamentType('일기토'):
$tnmt_type = "일기토";
$color = "cyan";
$tp = "strength";
$tp2 = "무력";
$tp3 = "strength";
break;
case 3:
$tnmt_type = "<font color=cyan>설전</font>";
case convertTournamentType('설전'):
$tnmt_type = "설전";
$color = "cyan";
$tp = "intel";
$tp2 = "지력";
$tp3 = "intel";
break;
default:
throw new \RuntimeException('Invalid tnmt_type');
}
$bettingID = $gameStor->last_tournament_betting_id ?? 0;
$myBet = [];
$globalBet = [];
if ($bettingID != 0) {
$betting = $bettingID != 0 ? new Betting($bettingID) : null;
$info = $betting->getInfo();
foreach ($db->queryAllLists(
'SELECT general_id, user_id, amount, betting_type FROM ng_betting WHERE betting_id = %i',
$bettingID
) as [$betGeneralID, $userID, $amount, $bettingTypeKey]) {
$bettingKey = Json::decode($bettingTypeKey)[0];
if ($betGeneralID == $generalID) {
$myBet[$bettingKey] = $amount;
}
if (key_exists($bettingKey, $globalBet)) {
$globalBet[$bettingKey] += $amount;
} else {
$globalBet[$bettingKey] = $amount;
}
}
} else {
$info = getDummyBettingInfo($tnmt_type);
}
$myBetTotal = array_sum($myBet);
$globalBetTotal = array_sum($globalBet);
$str1 = getTournament($admin['tournament']);
$str2 = getTournamentTime();
if ($str2) {
@@ -90,6 +120,11 @@ if ($str3) {
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printDist('ts', ['common', 'betting']) ?>
<?= WebUtil::printStaticValues([
'staticValues'=>[
'bettingID'=> $bettingID
]
])?>
</head>
<body>
@@ -104,7 +139,7 @@ if ($str3) {
</tr>
<tr>
<td colspan=16 align=center>
<font color=white size=6><?= $tnmt_type ?> (<?= $str1 . $str2 . $str3 ?>)</font>
<font color=white size=6><span style="color:<?= $color ?>"><?= $tnmt_type ?></span> (<?= $str1 . $str2 . $str3 ?>)</font>
</td>
</tr>
<tr>
@@ -265,7 +300,6 @@ if ($str3) {
for ($i = 0; $i < 8; $i++) {
echo "<td colspan=2>{$gen[$i]}</td>";
}
echo "
</tr>
<tr align=center>";
@@ -273,7 +307,7 @@ if ($str3) {
for ($i = 0; $i < 8; $i++) {
$cent[$i] = "<font color=white>";
}
$generalList = $db->query('SELECT npc,name,win from tournament where grp>=20 order by grp, grp_no LIMIT 16');
$generalList = $db->query('SELECT npc,name,win,leadership,strength,intel,leadership+strength+intel as total from tournament where grp>=20 order by grp, grp_no LIMIT 16');
while (count($generalList) < 16) {
$generalList[] = [
'name' => '-',
@@ -293,6 +327,11 @@ if ($str3) {
$line[$i] = "<font color=white>";
}
$gen[$i] = $general['name'];
if (array_key_exists($tp, $general)) {
$stat[$i] = $general[$tp];
} else {
$stat[$i] = "-";
}
}
for ($i = 0; $i < 8; $i++) {
$cent[$i] = $cent[$i] . "┻" . "</font>";
@@ -300,45 +339,48 @@ if ($str3) {
$line[$i * 2 + 1] = $line[$i * 2 + 1] . "━━┓" . "</font>";
echo "<td colspan=2>{$line[$i * 2]}{$cent[$i]}{$line[$i * 2 + 1]}</td>";
}
echo "
</tr>
<tr align=center>";
for ($i = 0; $i < 16; $i++) {
echo "<td width=70>{$gen[$i]}</td>";
}
$bet = [];
$gold = [];
for ($i = 0; $i < 16; $i++) {
if ($globalBet[$i] == 0) {
$bet[$i] = "∞";
} else {
$bet[$i] = round($globalBetTotal / $globalBet[$i], 2);
}
}
for ($i = 0; $i < 16; $i++) {
if (!is_numeric($bet[$i])) {
$gold[$i] = 0;
} else {
$gold[$i] = Util::round($myBet[$i] * $bet[$i]);
}
}
?>
</tr>
<tr align=center>
<?php for ($i = 0; $i < 16; $i++) { ?>
<td width=70><?= $gen[$i] ?></td>
<?php } ?>
</tr>
<tr align=center>
<?php for ($i = 0; $i < 16; $i++) { ?>
<td width=70 style="font-size: 14px"><?= $stat[$i] ?></td>
<?php } ?>
</tr>
</table>
<table align=center width=1120 class='tb_layout bg0'>
<table align=center width=1120 style="table-layout: fixed" class='tb_layout bg0'>
<tr align=center>
<td height=10 colspan=16></td>
</tr>
<?php
$bet = [];
$gold = [];
$keyMap = [];
foreach ($info->candidates as $key => $candidate) {
$keyMap[$candidate->aux['idx']] = $key;
}
foreach ($globalBet as $key => $amount) {
if ($amount == 0) {
$bet[$key] = "∞";
$gold[$key] = 0;
} else {
$rewardRatio = round($globalBetTotal / $amount, 2);
$bet[$key] = $rewardRatio;
$gold[$key] = $rewardRatio * ($myBet[$key] ?? 0);
}
}
echo "
<tr align=center>";
for ($i = 0; $i < 16; $i++) {
echo "<td width=70><font color=skyblue>{$bet[$i]}</font></td>";
foreach (range(0, 15) as $i) {
$amount = $bet[$keyMap[$i] ?? -1] ?? 0;
echo "<td width=70><font color=skyblue>{$amount}</font></td>";
}
?>
</tr>
@@ -362,8 +404,9 @@ if ($str3) {
</tr>
<tr align=center>
<?php
for ($i = 0; $i < 16; $i++) {
echo "<td><font color=orange>{$myBet[$i]}</font></td>";
foreach (range(0, 15) as $i) {
$amount = $myBet[$keyMap[$i] ?? -1] ?? 0;
echo "<td><font color=orange>{$amount}</font></td>";
}
?>
</tr>
@@ -387,8 +430,9 @@ if ($str3) {
</tr>
<tr align=center>
<?php
for ($i = 0; $i < 16; $i++) {
echo "<td><font color=cyan>{$gold[$i]}</font></td>";
foreach (range(0, 15) as $i) {
$amount = $gold[$keyMap[$i] ?? -1] ?? 0;
echo "<td><font color=cyan>{$amount}</font></td>";
}
echo "
@@ -399,10 +443,11 @@ if ($str3) {
echo "
<tr align=center>";
for ($i = 0; $i < 16; $i++) {
foreach (range(0, 15) as $i) {
$key = $keyMap[$i] ?? -1;
echo "
<td>
<select size=1 id='target_{$i}' style=color:white;background-color:black;>
<select size=1 id='target_{$key}' style=color:white;background-color:black;>
<option style=color:white; value=10>금10</option>
<option style=color:white; value=20>금20</option>
<option style=color:white; value=50>금50</option>
@@ -418,9 +463,10 @@ if ($str3) {
</tr>
<tr align=center>";
for ($i = 0; $i < 16; $i++) {
foreach (range(0, 15) as $i) {
$key = $keyMap[$i] ?? -1;
echo "
<td><input type=button class='submitBtn' data-target='{$i}' value=베팅! style=width:100%;color:white;background-color:black;></td>";
<td><input type=button class='submitBtn' data-target='{$key}' value=베팅! style=width:100%;color:white;background-color:black;></td>";
}
echo "</tr>";
@@ -507,14 +553,14 @@ if ($str3) {
<td align=center>勝</td>
</tr>
<?php
$prizeColumn = "{$rankColumn}p";
$gameColumn = "{$rankColumn}g";
$winColumn = "{$rankColumn}w";
$drawColumn = "{$rankColumn}d";
$loseColumn = "{$rankColumn}l";
$prizeColumn = RankColumn::from("{$rankColumn}p");
$gameColumn = RankColumn::from("{$rankColumn}g");
$winColumn = RankColumn::from("{$rankColumn}w");
$drawColumn = RankColumn::from("{$rankColumn}d");
$loseColumn = RankColumn::from("{$rankColumn}l");
$tournamentRankerList = General::createGeneralObjListFromDB(
$db->queryFirstColumn('SELECT general_id FROM rank_data WHERE `type`= %s ORDER BY value DESC LIMIT 40', $gameColumn),
[$prizeColumn, $gameColumn, $winColumn, $drawColumn, $loseColumn, 'leadership', 'strength', 'intel', 'no', 'npc', 'name'],
$db->queryFirstColumn('SELECT general_id FROM rank_data WHERE `type`= %s ORDER BY value DESC LIMIT 40', $gameColumn->value),
[$prizeColumn->value, $gameColumn->value, $winColumn->value, $drawColumn->value, $loseColumn->value, 'leadership', 'strength', 'intel', 'no', 'npc', 'name'],
0
);
usort($tournamentRankerList, function (General $lhs, General $rhs) use ($gameColumn, $winColumn, $drawColumn, $loseColumn) {
+2 -1
View File
@@ -337,6 +337,7 @@ $templates = new \League\Plates\Engine('templates');
'ourGeneral' => $ourGeneral,
'iconPath' => GetImageURL($general['imgsvr']) . '/' . $general['picture'],
'isNPC' => $isNPC,
'npc' => $general['npc'],
'wounded' => $wounded,
'name' => $name,
'nameText' => $nameText,
@@ -364,7 +365,7 @@ $templates = new \League\Plates\Engine('templates');
}
$generalsName = array_map(function ($gen) {
return getColoredName($gen['name'], $gen['npc']);
return formatName($gen['name'], $gen['npc']);
}, $generals);
$enemyCrew = 0;
-236
View File
@@ -1,236 +0,0 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
increaseRefresh("중원정보", 1);
$mapTheme = $gameStor->map_theme ?? 'che';
$me = $db->queryFirstRow('SELECT no,nation FROM general WHERE owner=%i', $userID);
$myNationID = $me['nation'];
$nations = array_filter(getAllNationStaticInfo(), function (array $nation) {
return $nation['level'];
});
uasort($nations, function (array $lhs, array $rhs) {
return - ($lhs['power'] <=> $rhs['power']);
});
$nationCnt = count($nations);
foreach ($db->queryAllLists('SELECT nation, count(city) FROM city WHERE nation != 0 GROUP BY nation') as [$nationID, $cityCnt]) {
$nations[$nationID]['city_cnt'] = $cityCnt;
}
$realConflict = [];
foreach ($db->queryAllLists('SELECT city, `name`, conflict FROM city WHERE conflict!=%s', '{}') as [
$cityID,
$cityName,
$rawConflict
]) {
$rawConflict = Json::decode($rawConflict);
if (count($rawConflict) < 2) {
continue;
}
$sum = array_sum($rawConflict);
$conflict = [];
foreach ($rawConflict as $nationID => $killnum) {
$conflict[$nationID] = [
'killnum' => $killnum,
'percent' => round(100 * $killnum / $sum, 1),
'name' => $nations[$nationID]['name'],
'color' => $nations[$nationID]['color']
];
}
$realConflict[] = [$cityID, $cityName, $conflict];
};
$diplomacyList = [];
foreach ($db->queryAllLists('SELECT me, you, state FROM diplomacy') as [$me, $you, $state]) {
if (!key_exists($me, $diplomacyList)) {
$diplomacyList[$me] = [];
}
$diplomacyList[$me][$you] = $state;
}
$cellWidth = intdiv(888, max(1, $nationCnt));
$defaultStateChar = '?';
$sameNationStateChar = '';
$infomativeStateCharMap = [
0 => '<span style="color:red;">★</span>',
1 => '<span style="color:magenta;">▲</span>',
2 => 'ㆍ',
7 => '<span style="color:green;">@</span>'
];
$neutralStateCharMap = [
0 => '<span style="color:red;">★</span>',
1 => '<span style="color:magenta;">▲</span>'
];
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 중원 정보</title>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printJS('d_shared/base_map.js') ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<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::printCSS('css/history.css') ?>
<?= WebUtil::printDist('ts', ['common', 'map']) ?>
<script>
window.serverNick = '<?= DB::prefix() ?>';
window.serverID = '<?= UniqueConst::$serverID ?>';
$(function() {
reloadWorldMap({
neutralView: true,
showMe: true,
useCachedMap: true
});
});
</script>
</head>
<body>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td>중 원 정 보<br><?= backButton() ?></td>
</tr>
</table>
<br>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td colspan=<?= $nationCnt + 1 ?> align=center bgcolor=blue>외 교 현 황</td>
</tr>
<tr>
<td align=center width=130 style=background-color:<?= GameConst::$basecolor2 ?>;>&nbsp;</td>
<?php foreach ($nations as $nation) : ?>
<td align=center width=<?= $cellWidth ?> style='background-color:<?= $nation['color'] ?>;color:<?= newColor($nation['color']) ?>'><?= $nation['name'] ?></td>
<?php endforeach; ?>
</tr>
<?php foreach ($nations as $me => $meNation) : ?>
<tr style='text-align:center;'>
<td align=center style='background-color:<?= $meNation['color'] ?>;color:<?= newColor($meNation['color']) ?>'><?= $meNation['name'] ?></td>
<?php foreach (array_keys($nations) as $you) : ?>
<td <?= ($me == $myNationID || $you == $myNationID) ? 'style="background-color:' . GameConst::$basecolor3 . '"' : '' ?>><?php
if ($me == $you) {
echo $sameNationStateChar;
} else if ($me == $myNationID || $you == $myNationID || $session->userGrade >= 5) {
echo $infomativeStateCharMap[$diplomacyList[$me][$you]] ?? $defaultStateChar;
} else {
echo $neutralStateCharMap[$diplomacyList[$me][$you]] ?? $defaultStateChar;
}
?></td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
<tr>
<td colspan=<?= $nationCnt + 1 ?> align=center>불가침 : <font color=limegreen>@</font>, 통상 : ㆍ, 선포 : <font color=magenta>▲</font>, 교전 : <font color=red>★</font>
</td>
</tr>
</table>
<?php if ($realConflict) : ?>
<br>
<table align='center' width=1000 class='tb_layout bg0'>
<tr>
<td colspan=2 align=center bgcolor=magenta>분 쟁 현 황</td>
</tr>
<?php foreach ($realConflict as list($cityID, $cityName, $conflict)) : ?>
<tr>
<td align=center width=48><?= $cityName ?></td>
<td style='width:948px;position:relative;'>
<table class='tb_layout bg0' style='width:100%;'>
<?php foreach ($conflict as $item) : ?>
<tr>
<td width=130 align=right style='color:<?= newColor($item['color']) ?>;background-color:<?= $item['color'] ?>;'><?= $item['name'] ?>&nbsp;</td>
<td width=48 align=right><?= (float)$item['percent'] ?> %&nbsp;</td>
<td width=*>
<div style='display:inline-block;width:<?= $item['percent'] ?>%;background-color:<?= $item['color'] ?>;'>&nbsp;</div>
</td>
</tr>
<?php endforeach; ?>
</table>
</td>
</tr>
<?php endforeach; ?>
<tr>
<td colspan=2 height=5 class='bg1'></td>
</tr>
</table>
<?php endif; ?>
<br>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td colspan=5 align=center bgcolor=green>
<font size=3>중 원 지 도</font>
</td>
</tr>
<tr>
<td width=698 height=420>
<?= getMapHtml($mapTheme) ?>
</td>
<td id='nation_list_frame'>
<table id='nation_list'>
<thead>
<tr>
<th width=130>국명</th>
<th width=70>국력</th>
<th width=45>장수</th>
<th width=45>속령</th>
</tr>
</thead>
<tbody>
<?php foreach ($nations as $nation) : ?>
<tr>
<td><span style='color:<?= newColor($nation['color']) ?>;background-color:<?= $nation['color'] ?>'><?= $nation['name'] ?></td>
<td style='text-align:right'><?= number_format($nation['power']) ?></td>
<td style='text-align:right'><?= number_format($nation['gennum']) ?></td>
<td style='text-align:right'><?= number_format($nation['city_cnt']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot></tfoot>
</table>
</td>
</tr>
</table>
<br>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td><?= backButton() ?></td>
</tr>
<tr>
<td><?= banner() ?></td>
</tr>
</table>
</body>
</html>
+1 -1
View File
@@ -172,7 +172,7 @@ $templates = new \League\Plates\Engine('templates');
$general['expLevelText'] = getExpLevel($general['experience']);
$general['nameText'] = getColoredName($general['name'], $general['npc']);
$general['nameText'] = formatName($general['name'], $general['npc']);
$general['modeText'] = formatDefenceTrain($general['defence_train']);
$general['crewtypeText'] = GameUnitConst::byId($general['crewtype'])->name ?? '-';
+72 -58
View File
@@ -71,7 +71,8 @@ $sel = [$type => "selected"];
</table>
<?php
$nation = getNationStaticInfo($me['nation']); //국가정보
$nation = $db->queryFirstRow('SELECT nation, name, color, type, level, capital, gennum, `power`, `rate` from nation WHERE nation = %i', $nationID); //국가정보
$nationTypeObj = buildNationTypeClass($nation['type']);
$officerList = [];
foreach ($db->query('SELECT no,name,npc,city,officer_level,officer_city,belong FROM general WHERE nation = %i AND 2 <= officer_level AND officer_level <= 4', $nationID) as $officer) {
@@ -82,6 +83,17 @@ $sel = [$type => "selected"];
$officerList[$officerCityID][$officer['officer_level']] = $officer;
}
$generalList = $db->query('SELECT npc, name, city FROM general WHERE nation = %i', $me['nation']);
$cityGeneralList = [];
foreach ($generalList as $general) {
$cityID = $general['city'];
if (!key_exists($cityID, $cityGeneralList)) {
$cityGeneralList[$cityID] = [];
}
$cityGeneralList[$cityID][] = formatName($general['name'], $general['npc']);
}
$cityList = $db->query('SELECT *,pop/pop_max as poprate from city where nation=%i', $nationID);
@@ -171,8 +183,12 @@ $sel = [$type => "selected"];
];
$cityOfficerList = $officerList[$cityID] ?? [];
$effectiveOfficerCnt = 0;
foreach ($cityOfficerList as $cityOfficer) {
$officerName[$cityOfficer['officer_level']] = getColoredName($cityOfficer['name'], $cityOfficer['npc']);
if ($cityOfficer['city'] == $cityID) {
$effectiveOfficerCnt += 1;
}
$officerName[$cityOfficer['officer_level']] = formatName($cityOfficer['name'], $cityOfficer['npc']);
}
if ($type == 10 && $city['region'] != $region) {
@@ -187,62 +203,60 @@ $sel = [$type => "selected"];
$city['trade'] = "- ";
}
echo "
<table align=center width=1000 class='tb_layout bg2'>
<tr>
<td colspan=12 style=color:" . newColor($nation['color']) . "; bgcolor={$nation['color']}><font size=2>【 " . CityConst::$regionMap[$city['region']] . " | " . CityConst::$levelMap[$city['level']] . " 】 {$city['name']}</font></td>
</tr>
<tr>
<td align=center width=46 class='bg1'>주민</td>
<td align=center width=140>{$city['pop']}/{$city['pop_max']}</td>
<td align=center width=46 class='bg1'>농업</td>
<td align=center width=140>{$city['agri']}/{$city['agri_max']}</td>
<td align=center width=46 class='bg1'>상업</td>
<td align=center width=140>{$city['comm']}/{$city['comm_max']}</td>
<td align=center width=46 class='bg1'>치안</td>
<td align=center width=140>{$city['secu']}/{$city['secu_max']}</td>
<td align=center width=46 class='bg1'>수비</td>
<td align=center width=140>{$city['def']}/{$city['def_max']}</td>
<td align=center width=46 class='bg1'>성벽</td>
<td align=center width=140>{$city['wall']}/{$city['wall_max']}</td>
</tr>
<tr>
<td align=center class='bg1'>민심</td>
<td align=center>" . round($city['trust'], 1) . "</td>
<td align=center class='bg1'>시세</td>
<td align=center>{$city['trade']}%</td>
<td align=center class='bg1'>인구</td>
<td align=center>" . round($city['pop'] / $city['pop_max'] * 100, 2) . " %</td>
<td align=center class='bg1'>태수</td>
<td align=center>";
echo $officerName[4];
echo "</td>
<td align=center class='bg1'>군사</td>
<td align=center>";
echo $officerName[3];
echo "</td>
<td align=center class='bg1'>종사</td>
<td align=center>";
echo $officerName[2];
echo "</td>
</tr>
<tr>
<td align=center class='bg1'>장수</td>
<td colspan=11>";
$generalList = $db->query('SELECT npc, name FROM general WHERE city = %i AND nation = %i', $city['city'], $me['nation']);
if (!$generalList) {
echo "-";
}
foreach ($generalList as $general) {
echo getColoredName($general['name'], $general['npc']) . ', ';
}
echo "
</td>
</tr>
</table>
";
}
$cityGoldIncome = $nation['rate'] / 20 * calcCityGoldIncome($city, $effectiveOfficerCnt, $nation['capital'] == $cityID, $nation['level'], $nationTypeObj);
$cityRiceIncome = $nation['rate'] / 20 * calcCityRiceIncome($city, $effectiveOfficerCnt, $nation['capital'] == $cityID, $nation['level'], $nationTypeObj);
$cityWallIncome = $nation['rate'] / 20 * calcCityWallRiceIncome($city, $effectiveOfficerCnt, $nation['capital'] == $cityID, $nation['level'], $nationTypeObj);
?>
<table align=center width=1000 class='tb_layout bg2'>
<tr>
<td colspan=10 style="color:<?= newColor($nation['color']) ?>; background-color:<?= $nation['color'] ?>;">
<font size=2>【 <?= CityConst::$regionMap[$city['region']] ?> | <?= CityConst::$levelMap[$city['level']] ?> 】 <?= $city['name'] ?></font>
</td>
</tr>
<tr style='text-align:center;'>
<td width=60 class='bg1'>주민</td>
<td width=140 class='pop-value'><?= $city['pop'] ?>/<?= $city['pop_max'] ?></td>
<td width=60 class='bg1'>인구율</td>
<td width=140 class='pop-prop-value'><?= round($city['pop'] / $city['pop_max'] * 100, 2) ?>%</td>
<td width=60 class='bg1'>자금 수입</td>
<td width=140 class='gold-income'><?= number_format($cityGoldIncome) ?></td>
<td width=60 class='bg1'>군량 수입</td>
<td width=140 class='rice-income'><?= number_format($cityRiceIncome) ?></td>
<td width=60 class='bg1'>둔전 수입</td>
<td width=140 class='wall-income'><?= number_format($cityWallIncome) ?></td>
</tr>
<tr style='text-align:center;'>
<td class='bg1'>농업</td>
<td class='agri-value'><?= $city['agri'] ?>/<?= $city['agri_max'] ?></td>
<td class='bg1'>상업</td>
<td class='comm-value'><?= $city['comm'] ?>/<?= $city['comm_max'] ?></td>
<td class='bg1'>치안</td>
<td class='secu-value'><?= $city['secu'] ?>/<?= $city['secu_max'] ?></td>
<td class='bg1'>수비</td>
<td class='def-value'><?= $city['def'] ?>/<?= $city['def_max'] ?></td>
<td class='bg1'>성벽</td>
<td class='wall-value'><?= $city['wall'] ?>/<?= $city['wall_max'] ?></td>
</tr>
<tr style='text-align:center;'>
<td class='bg1'>민심</td>
<td class='trust-value'><?= round($city['trust'], 1) ?></td>
<td class='bg1'>시세</td>
<td class='trade-value'><?= $city['trade'] ?>%</td>
<td class='bg1'>태수</td>
<td class='officer-4-value'><?= $officerName[4] ?></td>
<td class='bg1'>군사</td>
<td class='officer-3-value'><?= $officerName[3] ?></td>
<td class='bg1'>종사</td>
<td class='officer-2-value'><?= $officerName[2] ?></td>
</tr>
<tr>
<td style='text-align:center;' class='bg1'>장수</td>
<td colspan=9 class='city-generals'><?= key_exists($cityID, $cityGeneralList) ? join(', ', $cityGeneralList[$cityID]) : '-' ?></td>
</tr>
</table>
<?php } ?>
<table align=center width=1000 class='tb_layout bg0 anchor'>
<tr>
@@ -252,7 +266,7 @@ $sel = [$type => "selected"];
<td><?= banner() ?></td>
</tr>
</table>
<div id="helper_genlist" style="display:none;"></div>
</body>
<div id="helper_genlist" style="display:none;"></div>
</html>
+28 -7
View File
@@ -50,9 +50,18 @@ $use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn') ?? 1;
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=500" />
<title><?= UniqueConst::$serverName ?>: 내정보</title>
<script>
var availableDieImmediately = <?= $availableDieImmediately ? 'true' : 'false' ?>;
</script>
<?= WebUtil::printStaticValues([
'availableDieImmediately' => $availableDieImmediately,
'staticValues' => [
'items' => Util::mapWithKey(fn (string $key, BaseItem $item) => [
'name' => $item->getName(),
'rawName' => $item->getRawName(),
'className' => $item->getRawClassName(),
'cost' => $item->getCost(),
'isBuyable' => $item->isBuyable(),
], $me->getItems())
]
]) ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
@@ -72,8 +81,8 @@ $use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn') ?? 1;
</div>
<div class="col col-12 col-md-6">
<div class="row">
<div class="col" style='padding-left:4ch;'>
<div class="row mx-0 gx-0">
<div class="col" style='padding-left:2ch;'>
토너먼트 【
<input type=radio class='tnmt' name=tnmt value=0 <?= $me->getVar('tnmt') == 0 ? "checked" : ""; ?>>수동참여
<input type=radio class='tnmt' name=tnmt value=1 <?= $me->getVar('tnmt') == 1 ? "checked" : ""; ?>>자동참여
@@ -94,8 +103,8 @@ $use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn') ?? 1;
<option value=0 <?= (!$use_auto_nation_turn) ? "selected" : ""; ?>>허용 안함</option>
</select>】<br>
∞<span style='color:orange'>수뇌가 되었을 때 휴식 턴이어도 적당한 턴을 알아서 넣는 것을 허용합니다.</span><br><br>
<?php else: ?>
<input type="hidden" id='use_auto_nation_turn' name='use_auto_nation_turn' value="1"/>
<?php else : ?>
<input type="hidden" id='use_auto_nation_turn' name='use_auto_nation_turn' value="1" />
<?php endif; ?>
수비 【<select id='defence_train' name='defence_train'>
<?php foreach ([90, 80, 60, 40] as $targetDefenceTrain) : ?>
@@ -138,6 +147,18 @@ $use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn') ?? 1;
</div>
</div>
</div>
<div class="row">
<div class="col">아이템 파기</div>
</div>
<div class="row mx-1">
<div class="btn-group" role="group">
<?php foreach ($me->getItems() as $itemKey => $item) : ?>
<button type="button" data-item-type='<?=$itemKey?>' class="drop-item-btn btn btn-primary <?= $item->getName() == '-' ? 'disabled' : '' ?>"><?= $item->getName() ?></button>
<?php endforeach; ?>
</div>
</div>
<br>
개인용 CSS<br>
+73 -23
View File
@@ -15,6 +15,7 @@ increaseRefresh("토너먼트", 1);
TurnExecutionHelper::executeAllCommand();
$me = $db->queryFirstRow('select no,tournament,con,turntime from general where owner=%i', $userID);
$generalID = $session->generalID;
$admin = $gameStor->getValues(['tournament', 'phase', 'tnmt_msg', 'tnmt_type', 'develcost', 'tnmt_trig']);
@@ -25,34 +26,76 @@ if ($con >= 2) {
}
switch ($admin['tnmt_type']) {
default:
throw new \RuntimeException('invalid tnmt_type');
case 0:
$tnmt_type = "<font color=cyan>전력전</font>";
case convertTournamentType('전력전'):
$tnmt_type = "전력전";
$color = 'cyan';
$tp = "total";
$tp2 = "종합";
$tp3 = "total";
break;
case 1:
$tnmt_type = "<font color=cyan>통솔전</font>";
case convertTournamentType('통솔전'):
$tnmt_type = "통솔전";
$color = 'cyan';
$tp = "leadership";
$tp2 = "통솔";
$tp3 = "leadership";
break;
case 2:
$tnmt_type = "<font color=cyan>일기토</font>";
case convertTournamentType('일기토'):
$tnmt_type = "일기토";
$color = 'cyan';
$tp = "strength";
$tp2 = "무력";
$tp3 = "strength";
break;
case 3:
$tnmt_type = "<font color=cyan>설전</font>";
case convertTournamentType('설전'):
$tnmt_type = "설전";
$color = 'cyan';
$tp = "intel";
$tp2 = "지력";
$tp3 = "intel";
break;
default:
throw new \RuntimeException('invalid tnmt_type');
}
$bettingID = $gameStor->last_tournament_betting_id ?? 0;
if ($bettingID != 0) {
$betting = $bettingID != 0 ? new Betting($bettingID) : null;
$info = $betting->getInfo();
} else {
$info = getDummyBettingInfo($tnmt_type);
}
$myBet = [];
$globalBet = [];
if ($bettingID != 0) {
$betting = $bettingID != 0 ? new Betting($bettingID) : null;
$info = $betting->getInfo();
foreach ($db->queryAllLists(
'SELECT general_id, user_id, amount, betting_type FROM ng_betting WHERE betting_id = %i',
$bettingID
) as [$betGeneralID, $userID, $amount, $bettingTypeKey]) {
$bettingKey = Json::decode($bettingTypeKey)[0];
if ($betGeneralID == $generalID) {
$myBet[$bettingKey] = $amount;
}
if (key_exists($bettingKey, $globalBet)) {
$globalBet[$bettingKey] += $amount;
} else {
$globalBet[$bettingKey] = $amount;
}
}
} else {
$info = getDummyBettingInfo($tnmt_type);
}
$myBetTotal = array_sum($myBet);
$globalBetTotal = array_sum($globalBet);
?>
<!DOCTYPE html>
<html>
@@ -209,7 +252,7 @@ switch ($admin['tnmt_type']) {
</tr>
<tr>
<td colspan=8 align=center>
<font color=white size=6><?= $tnmt_type ?> (<?= $str1 . $str2 . $str3 ?>)</font>
<font color=white size=6><span style="color:<?= $color ?>"><?= $tnmt_type ?></span> (<?= $str1 . $str2 . $str3 ?>)</font>
</td>
</tr>
<tr>
@@ -418,24 +461,31 @@ switch ($admin['tnmt_type']) {
echo "
</tr>";
$globalBet = $db->queryFirstList('SELECT * FROM betting WHERE general_id = 0') ?? [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,];
$globalBet = array_splice($globalBet, -16);
$globalBetTotal = array_sum($globalBet);
$admin = $gameStor->getValues(['tournament', 'phase']);
$bet = [];
for ($i = 0; $i < 16; $i++) {
if ($globalBet[$i] == 0) {
$bet[$i] = '∞';
continue;
$gold = [];
$keyMap = [];
foreach ($info->candidates as $key => $candidate) {
$keyMap[$candidate->aux['idx']] = $key;
}
foreach ($globalBet as $key => $amount) {
if ($amount == 0) {
$bet[$key] = "∞";
$gold[$key] = 0;
} else {
$rewardRatio = round($globalBetTotal / $amount, 2);
$bet[$key] = $rewardRatio;
$gold[$key] = $rewardRatio * ($myBet[$key] ?? 0);
}
$bet[$i] = round($globalBetTotal / $globalBet[$i], 2);
}
echo "
<tr align=center>";
for ($i = 0; $i < 16; $i++) {
echo "<td><font color=skyblue>{$bet[$i]}</font></td>";
foreach (range(0, 15) as $i) {
$amount = $bet[$keyMap[$i] ?? -1] ?? 0;
echo "<td><font color=skyblue>{$amount}</font></td>";
}
echo "
@@ -469,7 +519,7 @@ switch ($admin['tnmt_type']) {
printRow($k, $general['npc'], $general['name'], $general[$tp], $general['game'], $general['win'], $general['draw'], $general['lose'], $general['gd'], $general['gl'], $general['prmt']);
}
foreach (Util::range(count($generalList), 4) as $idx) {
printRow($idx, '', '', '', '', '', '', '', '', '', '');
printRow($idx, 0, '', '', '', '', '', '', '', '', '');
}
echo "
</table>
@@ -496,7 +546,7 @@ switch ($admin['tnmt_type']) {
printRow($k, $general['npc'], $general['name'], $general[$tp], $general['game'], $general['win'], $general['draw'], $general['lose'], $general['gd'], $general['gl'], $general['prmt']);
}
foreach (Util::range(count($generalList), 8) as $idx) {
printRow($idx, '', '', '', '', '', '', '', '', '', '');
printRow($idx, 0, '', '', '', '', '', '', '', '', '');
}
echo "
</table>
+4 -2
View File
@@ -98,8 +98,8 @@ if($btn == '참가') {
], 'no=%i', $general['no']);
}
$grpCount = $db->queryFirstField('SELECT count(*) FROM tournament where grp<10 GROUP BY grp HAVING count(*)=8');
if($grpCount >= 8) {
$grpCount = $db->queryFirstColumn('SELECT count(grp) FROM tournament where grp<10 GROUP BY grp;');
if(min($grpCount) >= 8) {
$gameStor->tournament = 2;
$gameStor->phase = 0;
}
@@ -225,6 +225,8 @@ if($btn == "자동개최설정") {
finallyAll($admin['tnmt_type'], $admin['tournament'], $admin['phase']);
} elseif($btn == "배정") {
final16set();
$phase = 0;
startBetting($admin['tnmt_type'], 720);
} elseif($btn == "베팅마감") {
$dt = date("Y-m-d H:i:s", time() + 60);
$gameStor->tournament=7;
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 B

+4 -6
View File
@@ -1,5 +1,3 @@
@charset "UTF-8";
.world_map {
width: 700px;
background: black;
@@ -69,11 +67,11 @@
}
.map_body .map_toggle_cityname::after {
content: "끄기"
content: " 끄기"
}
.map_body .map_toggle_cityname.active::after {
content: "켜기"
content: " 켜기"
}
.map_body .map_toggle_single_tap {
@@ -81,11 +79,11 @@
}
.map_body .map_toggle_single_tap::after {
content: "끄기"
content: " 끄기"
}
.map_body .map_toggle_single_tap.active::after {
content: "켜기"
content: " 켜기"
}
.world_map .city_tooltip {
+61 -51
View File
@@ -3,6 +3,8 @@
namespace sammo;
use DateTime;
use sammo\Enums\InheritanceKey;
use sammo\Enums\RankColumn;
use sammo\Event\Action;
require_once 'process_war.php';
@@ -171,7 +173,7 @@ function cityInfo(General $generalObj)
];
foreach ($db->query('SELECT `officer_level`, `name`, npc, no FROM general WHERE officer_city = %i', $cityID) as $officer) {
$officerName[$officer['officer_level']] = getColoredName($officer['name'], $officer['npc']);
$officerName[$officer['officer_level']] = formatName($officer['name'], $officer['npc']);
}
$city['officerName'] = $officerName;
@@ -199,8 +201,8 @@ function myNationInfo(General $generalObj)
$topChiefs = Util::convertArrayToDict($db->query('SELECT officer_level, no, name, npc FROM general WHERE nation = %i AND officer_level >= 11', $nationID), 'officer_level');
$level12Name = key_exists(12, $topChiefs) ? getColoredName($topChiefs[12]['name'], $topChiefs[12]['npc']) : '-';
$level11Name = key_exists(11, $topChiefs) ? getColoredName($topChiefs[11]['name'], $topChiefs[11]['npc']) : '-';
$level12Name = key_exists(12, $topChiefs) ? formatName($topChiefs[12]['name'], $topChiefs[12]['npc']) : '-';
$level11Name = key_exists(11, $topChiefs) ? formatName($topChiefs[11]['name'], $topChiefs[11]['npc']) : '-';
$impossibleStrategicCommandLists = [];
$strategicCommandLists = GameConst::$availableChiefCommand['전략'];
@@ -472,7 +474,8 @@ function getCommandTable(General $general)
return $result;
}
function getChiefCommandTable(General $general){
function getChiefCommandTable(General $general)
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->turnOnCache();
@@ -756,8 +759,8 @@ function generalInfo2(General $generalObj)
{
$general = $generalObj->getRaw();
$winRate = round($generalObj->getRankVar('killnum') / max($generalObj->getRankVar('warnum'), 1) * 100, 2);
$killRate = round($generalObj->getRankVar('killcrew') / max($generalObj->getRankVar('deathcrew'), 1) * 100, 2);
$winRate = round($generalObj->getRankVar(RankColumn::killnum) / max($generalObj->getRankVar(RankColumn::warnum), 1) * 100, 2);
$killRate = round($generalObj->getRankVar(RankColumn::killcrew) / max($generalObj->getRankVar(RankColumn::deathcrew), 1) * 100, 2);
$experienceBonus = $generalObj->onCalcStat($generalObj, 'experience', 10000) - 10000;
if ($experienceBonus > 0) {
@@ -821,9 +824,9 @@ function generalInfo2(General $generalObj)
</tr>
<tr>
<td width=64 style='text-align:center;' class='bg1'><b>전투</b></td>
<td width=132 style='text-align:center;'>{$generalObj->getRankVar('warnum')}</td>
<td width=132 style='text-align:center;'>{$generalObj->getRankVar(RankColumn::warnum)}</td>
<td width=48 style='text-align:center;' class='bg1'><b>계략</b></td>
<td width=98 style='text-align:center;'>{$generalObj->getRankVar('firenum')}</td>
<td width=98 style='text-align:center;'>{$generalObj->getRankVar(RankColumn::firenum)}</td>
<td width=48 style='text-align:center;' class='bg1'><b>사관</b></td>
<td width=98 style='text-align:center;'>{$general['belong']}년</td>
</tr>
@@ -831,17 +834,17 @@ function generalInfo2(General $generalObj)
<td style='text-align:center;' class='bg1'><b>승률</b></td>
<td style='text-align:center;'>{$winRate} %</td>
<td style='text-align:center;' class='bg1'><b>승리</b></td>
<td style='text-align:center;'>{$generalObj->getRankVar('killnum')}</td>
<td style='text-align:center;'>{$generalObj->getRankVar(RankColumn::killnum)}</td>
<td style='text-align:center;' class='bg1'><b>패배</b></td>
<td style='text-align:center;'>{$generalObj->getRankVar('deathnum')}</td>
<td style='text-align:center;'>{$generalObj->getRankVar(RankColumn::deathnum)}</td>
</tr>
<tr>
<td style='text-align:center;' class='bg1'><b>살상률</b></td>
<td style='text-align:center;'>{$killRate} %</td>
<td style='text-align:center;' class='bg1'><b>사살</b></td>
<td style='text-align:center;'>{$generalObj->getRankVar('killcrew')}</td>
<td style='text-align:center;'>{$generalObj->getRankVar(RankColumn::killcrew)}</td>
<td style='text-align:center;' class='bg1'><b>피살</b></td>
<td style='text-align:center;'>{$generalObj->getRankVar('deathcrew')}</td>
<td style='text-align:center;'>{$generalObj->getRankVar(RankColumn::deathcrew)}</td>
</tr>
</table>
<table width=498 class='tb_layout bg2 f_tnum'>
@@ -879,9 +882,9 @@ function generalInfo2(General $generalObj)
</table>";
}
function getOnlineNum()
function getOnlineNum(): int
{
return KVStorage::getStorage(DB::db(), 'game_env')->online;
return KVStorage::getStorage(DB::db(), 'game_env')->getValue('online') ?? 0;
}
function onlinegen(General $general)
@@ -1072,6 +1075,7 @@ function updateTraffic()
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['year', 'month', 'refresh', 'maxonline', 'maxrefresh']);
/** @var array{year:int,month:int,refresh:int,maxonline:int,maxrefresh:int} $admin */
//최다갱신자
$user = $db->queryFirstRow('select name,refresh from general order by refresh desc limit 1');
@@ -1121,7 +1125,7 @@ function CheckOverhead()
function isLock()
{
return DB::db()->queryFirstField("SELECT plock from plock limit 1") != 0;
return DB::db()->queryFirstField("SELECT plock from plock WHERE `type`='GAME'") != 0;
}
function tryLock(): bool
@@ -1133,7 +1137,7 @@ function tryLock(): bool
$db->update('plock', [
'plock' => 1,
'locktime' => TimeUtil::now(true)
], 'plock=0');
], 'plock=0 AND type="GAME"');
return $db->affectedRows() > 0;
}
@@ -1144,7 +1148,7 @@ function unlock(): bool
$db = DB::db();
$db->update('plock', [
'plock' => 0
], true);
], 'type="GAME"');
return $db->affectedRows() > 0;
}
@@ -1374,6 +1378,7 @@ function CheckHall($no)
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
//TODO: Enum타입을 두종류로 넣고, raw string이면 calcVar에서 받아오면?
$types = [
["experience", 'natural'],
["dedication", 'natural'],
@@ -1403,33 +1408,33 @@ function CheckHall($no)
$generalObj = General::createGeneralObjFromDB($no, null, 2);
$ttw = $generalObj->getRankVar('ttw');
$ttd = $generalObj->getRankVar('ttd');
$ttl = $generalObj->getRankVar('ttl');
$ttw = $generalObj->getRankVar(RankColumn::ttw);
$ttd = $generalObj->getRankVar(RankColumn::ttd);
$ttl = $generalObj->getRankVar(RankColumn::ttl);
$tlw = $generalObj->getRankVar('tlw');
$tld = $generalObj->getRankVar('tld');
$tll = $generalObj->getRankVar('tll');
$tlw = $generalObj->getRankVar(RankColumn::tlw);
$tld = $generalObj->getRankVar(RankColumn::tld);
$tll = $generalObj->getRankVar(RankColumn::tll);
$tsw = $generalObj->getRankVar('tsw');
$tsd = $generalObj->getRankVar('tsd');
$tsl = $generalObj->getRankVar('tsl');
$tsw = $generalObj->getRankVar(RankColumn::tsw);
$tsd = $generalObj->getRankVar(RankColumn::tsd);
$tsl = $generalObj->getRankVar(RankColumn::tsl);
$tiw = $generalObj->getRankVar('tiw');
$tid = $generalObj->getRankVar('tid');
$til = $generalObj->getRankVar('til');
$tiw = $generalObj->getRankVar(RankColumn::tiw);
$tid = $generalObj->getRankVar(RankColumn::tid);
$til = $generalObj->getRankVar(RankColumn::til);
$betWinGold = $generalObj->getRankVar('betwingold');
$betGold = Util::valueFit($generalObj->getRankVar('betgold'), 1);
$betWinGold = $generalObj->getRankVar(RankColumn::betwingold);
$betGold = Util::valueFit($generalObj->getRankVar(RankColumn::betgold), 1);
$win = $generalObj->getRankVar('killnum');
$war = Util::valueFit($generalObj->getRankVar('warnum'), 1);
$win = $generalObj->getRankVar(RankColumn::killnum);
$war = Util::valueFit($generalObj->getRankVar(RankColumn::warnum), 1);
$kill = $generalObj->getRankVar('killcrew');
$death = Util::valueFit($generalObj->getRankVar('deathcrew'), 1);
$kill = $generalObj->getRankVar(RankColumn::killcrew);
$death = Util::valueFit($generalObj->getRankVar(RankColumn::deathcrew), 1);
$killPerson = $generalObj->getRankVar('killcrew_person');
$deathPerson = Util::valueFit($generalObj->getRankVar('deathcrew_person'), 1);
$killPerson = $generalObj->getRankVar(RankColumn::killcrew_person);
$deathPerson = Util::valueFit($generalObj->getRankVar(RankColumn::deathcrew_person), 1);
$tt = Util::valueFit($ttw + $ttd + $ttl, 1);
$tl = Util::valueFit($tlw + $tld + $tll, 1);
@@ -1467,13 +1472,13 @@ function CheckHall($no)
if ($valueType === 'natural') {
$value = $generalObj->getVar($typeName);
} else if ($valueType === 'rank') {
$value = $generalObj->getRankVar($typeName);
$value = $generalObj->getRankVar(RankColumn::from($typeName));
} else if ($valueType === 'calc') {
$value = $calcVar[$typeName];
}
//승률,살상률인데 10회 미만 전투시 스킵
if (($typeName === 'winrate' || $typeName === 'killrate') && $generalObj->getRankVar('warnum') < 10) {
if (($typeName === 'winrate' || $typeName === 'killrate') && $generalObj->getRankVar(RankColumn::warnum) < 10) {
continue;
}
//토너승률인데 50회 미만시 스킵
@@ -1493,7 +1498,7 @@ function CheckHall($no)
continue;
}
//수익률인데 1000미만시 스킵
if ($typeName === 'betrate' && $generalObj->getRankVar('betgold') < 1000) {
if ($typeName === 'betrate' && $generalObj->getRankVar(RankColumn::betgold) < 1000) {
continue;
}
@@ -1581,7 +1586,7 @@ function giveRandomUniqueItem(General $general, string $acquireType): bool
}
}
foreach($db->queryAllLists('SELECT namespace, count(*) as cnt FROM `storage` WHERE namespace LIKE "ut_%" GROUP BY namespace') as [$uniqueNS, $cnt]){
foreach ($db->queryAllLists('SELECT namespace, count(*) as cnt FROM `storage` WHERE namespace LIKE "ut_%" GROUP BY namespace') as [$uniqueNS, $cnt]) {
$itemCode = substr($uniqueNS, 3);
$itemClass = buildItemClass($itemCode);
if (!$itemClass) {
@@ -1590,7 +1595,7 @@ function giveRandomUniqueItem(General $general, string $acquireType): bool
if ($itemClass->isBuyable()) {
continue;
}
$occupiedUnique[$itemCode] = ($occupiedUnique[$itemCode]??0) + $cnt;
$occupiedUnique[$itemCode] = ($occupiedUnique[$itemCode] ?? 0) + $cnt;
}
foreach (GameConst::$allItems as $itemType => $itemCategories) {
@@ -1616,7 +1621,8 @@ function giveRandomUniqueItem(General $general, string $acquireType): bool
if (!$availableUnique) {
if ($general->getAuxVar('inheritRandomUnique')) {
$general->setAuxVar('inheritRandomUnique', null);
$general->increaseInheritancePoint('previous', GameConst::$inheritItemRandomPoint);
$general->increaseInheritancePoint(InheritanceKey::previous, GameConst::$inheritItemRandomPoint);
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, -GameConst::$inheritItemRandomPoint);
$userLogger = new UserLogger($general->getVar('owner'));
$userLogger->push(sprintf("얻을 유니크가 없어 %d 포인트 반환", GameConst::$inheritItemRandomPoint), "inheritPoint");
}
@@ -1632,7 +1638,7 @@ function giveRandomUniqueItem(General $general, string $acquireType): bool
$relMonthByInit = Util::joinYearMonth($year, $month) - Util::joinYearMonth($initYear, $initMonth);
$availableBuyUnique = $relMonthByInit >= GameConst::$minMonthToAllowInheritItem;
if($availableBuyUnique){
if ($availableBuyUnique) {
$general->setAuxVar('inheritRandomUnique', null);
}
}
@@ -1686,7 +1692,8 @@ function rollbackInheritUniqueTrial(General $general, string $itemKey, string $r
//두 값이 general, KVStorage 둘다 있고, 이중에선 KVStorage 값을 기준으로 하자 따르자
[,, $amount] = $ownTrial;
$trialStor->deleteValue("u{$ownerID}");
$general->increaseInheritancePoint('previous', $amount);
$general->increaseInheritancePoint(InheritanceKey::previous, $amount);
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, -$amount);
LogText("선택유니크 롤백포인트:{$ownerID}", $amount);
$userLogger = new UserLogger($ownerID);
@@ -1751,12 +1758,11 @@ function tryInheritUniqueItem(General $general, string $acquireType = '아이템
$reasons[] = '이미 그 유니크를 가지고 있습니다.';
continue;
}
/*
if (!$ownItem->isBuyable()) {
$reasons[] = '이미 다른 유니크를 가지고 있습니다.';
continue;
}
*/
$availableCnt = $itemList[$itemKey];
$occupiedCnt = $db->queryFirstField('SELECT count(*) FROM general WHERE %b = %s', $itemType, $itemKey);
@@ -1858,6 +1864,9 @@ function tryInheritUniqueItem(General $general, string $acquireType = '아이템
$general->applyDB($db);
//같은 종류의 유니크를 입찰했을 수 있으니 한번 더 검사한다.
tryRollbackInheritUniqueItem($general);
return true;
}
@@ -1901,7 +1910,8 @@ function tryUniqueItemLottery(General $general, string $acquireType = '아이템
LogText("{$general->getName()}, {$general->getID()} 모든 아이템", $trialCnt);
if ($general->getAuxVar('inheritRandomUnique')) {
$general->setAuxVar('inheritRandomUnique', null);
$general->increaseInheritancePoint('previous', GameConst::$inheritItemRandomPoint);
$general->increaseInheritancePoint(InheritanceKey::previous, GameConst::$inheritItemRandomPoint);
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, -GameConst::$inheritItemRandomPoint);
$userLogger = new UserLogger($general->getVar('owner'));
$userLogger->push(sprintf("유니크를 얻을 공간이 없어 %d 포인트 반환", GameConst::$inheritItemRandomPoint), "inheritPoint");
}
@@ -2013,10 +2023,10 @@ function deleteNation(General $lord, bool $applyDB): array
// 전 장수 재야로
foreach ($nationGeneralList as $general) {
$general->setAuxVar(
'max_belong',
InheritanceKey::max_belong->value,
max(
$general->getVar('belong'),
$general->getAuxVar('max_belong') ?? 0
$general->getAuxVar(InheritanceKey::max_belong->value) ?? 0
)
);
$general->setVar('belong', 0);
@@ -2244,7 +2254,7 @@ function calcCityDistance(int $from, int $to, ?array $linkNationList): ?int
* @param $from 기준 도시 코드
* @param $to 대상 도시 코드
* @param $linkNationList 경로에 해당하는 국가 리스트
* @return array $dist=>[cityID, $nation] 배열 가장 앞이 가장 가까움
* @return array<int,array{int,int}[]> $dist=>[cityID, $nation] 배열 가장 앞이 가장 가까움
*/
function searchDistanceListToDest(int $from, int $to, array $linkNationList)
{
+2
View File
@@ -393,6 +393,7 @@ function setGeneralCommand(int $generalID, array $rawTurnList, string $command,
_setGeneralCommand($commandObj, $turnList);
return [
'result'=>true,
'brief'=>$commandObj->getBrief(),
'reason'=>'success'
];
}
@@ -474,6 +475,7 @@ function setNationCommand(int $generalID, array $turnList, string $command, ?arr
_setNationCommand($commandObj, $turnList);
return [
'result'=>true,
'brief'=>$commandObj->getBrief(),
'arg_test'=>true,
'reason'=>'success'
];
+32 -9
View File
@@ -64,6 +64,15 @@ function getNationLevel(int $level) {
][$level];
}
function convertTournamentType(string $type){
return[
'전력전'=>0,
'통솔전'=>1,
'일기토'=>2,
'설전'=>3,
][$type]??-1;
}
function getGenChar(?string $type) {
if($type === null){
return '-';
@@ -657,7 +666,7 @@ function getDexCall(int $dex) : string {
function getDexLevel(int $dex) : int {
if($dex < 0){
throw new \InvalidArgumentException();
return 0;
}
$retVal = 0;
@@ -692,21 +701,35 @@ function isConsumable(?string $item) : bool{
return $itemClass->isConsumable();
}
function getNameColor(int $npcType):?string{
if($npcType >= 2){
return 'cyan';
}
if($npcType == 1){
function getNPCColor(int $npc): ?string{
if ($npc == 1) {
return 'skyblue';
}
if ($npc == 4){
return 'deepskyblue';
}
if ($npc == 5){
return 'darkcyan';
}
if ($npc == 6){
return 'mediumaquamarine';
}
if ($npc > 1) {
return 'cyan';
}
return null;
}
function getColoredName(string $name, int $npcType):string{
$color = getNameColor($npcType);
function formatName(string $name, int $npc): string
{
$color = getNPCColor($npc);
if($color === null){
return $name;
}
return "<span style='color:{$color}'>{$name}</span>";
return "<span style='color:{$color}'>$name</span>";
}
function ConvertLog(?string $str, $type=1) : string {
+18 -52
View File
@@ -3,6 +3,8 @@
namespace sammo;
use Monolog\Logger;
use sammo\Enums\InheritanceKey;
use sammo\Enums\RankColumn;
/**
* 게임 룰에 해당하는 함수 모음
@@ -371,7 +373,7 @@ function postUpdateMonthly()
sum(pop)*sum(pop+agri+comm+secu+wall+def)/sum(pop_max+agri_max+comm_max+secu_max+wall_max+def_max)/100
) from city where nation=A.nation and supply=1
))
+(select SUM((ra.value + 1000)/(rb.value + 1000)*(CASE WHEN g.`leadership` >= 40 THEN g.`leadership` ELSE 0 END)*2 + (SQRT(g.intel * g.strength) * 2 + g.leadership / 2)/2)
+(select SUM((ra.value + 1000)/(rb.value + 1000)*(CASE WHEN g.`npc` < 2 THEN 1.2 ELSE 1 END)*(CASE WHEN g.`leadership` >= 40 THEN g.`leadership` ELSE 0 END)*2 + (SQRT(g.intel * g.strength) * 2 + g.leadership / 2)/2)
FROM general AS g
LEFT JOIN `rank_data` AS ra ON g.`no` = ra.general_id AND ra.`type` = \'killcrew_person\'
LEFT JOIN `rank_data` AS rb ON g.`no` = rb.general_id AND rb.`type` = \'deathcrew_person\'
@@ -702,7 +704,7 @@ function updateNationState()
if ($chiefID) {
$chiefObj = General::createGeneralObjFromDB($chiefID, ['belong', 'npc', 'aux'], 2);
$chiefObj->increaseInheritancePoint('unifier', 250 * $levelDiff);
$chiefObj->increaseInheritancePoint(InheritanceKey::unifier, 250 * $levelDiff);
$chiefObj->applyDB($db);
}
}
@@ -1022,15 +1024,20 @@ function checkEmperior()
$nationLogger = new ActionLogger(0, $nationID, $admin['year'], $admin['month']);
$nationLogger->pushNationalHistoryLog("<D><b>{$nationName}</b></>{$josaYi} 전토를 통일");
foreach (General::createGeneralObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc < 2')) as $genObj) {
$inheritPointManager = InheritancePointManager::getInstance();
$allUserGenerals = General::createGeneralObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc < 2'));
foreach ($allUserGenerals as $genObj) {
if ($genObj->getNationID() == $nationID) {
if ($genObj->getVar('officer_level') > 4) {
$genObj->increaseInheritancePoint('unifier', 2000);
$genObj->increaseInheritancePoint(InheritanceKey::unifier, 2000);
};
}
$genObj->mergeTotalInheritancePoint(true);
applyInheritanceUser($genObj->getVar('owner'));
$genObj->clearInheritancePoint();
}
processSumInheritPointRank();
foreach ($allUserGenerals as $genObj) {
$inheritPointManager->mergeTotalInheritancePoint($genObj, true);
$inheritPointManager->applyInheritanceUser($genObj->getVar('owner'));
$inheritPointManager->clearInheritancePoint($genObj);
}
$gameStor->isunited = 2;
@@ -1184,55 +1191,14 @@ function checkEmperior()
LogHistory();
}
function applyInheritanceUser(int $userID, bool $isRebirth = false): float
{
//FIXME: 은퇴, 사망, 천통 시점에 바로 반영한다면 여기가 아니라 general class로 이동하는 것이 옳음
//또한 굳이 merge, apply, clean 3단계를 거쳐야 할 이유도 없음
$rebirthDegraded = [
'dex' => 0.5,
];
$inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$userID}");
$totalPoint = 0;
$allPoints = $inheritStor->getAll();
if (!$allPoints || count($allPoints) == 0) {
//비었으므로 리셋 안함
return 0;
}
if (count($allPoints) == 1 && key_exists('previous', $allPoints)) {
//이미 리셋되었으므로 리셋 안함
return $allPoints['previous'][0];
}
$userLogger = new UserLogger($userID);
$previousPoint = ($allPoints['previous'] ?? [0, 0])[0];
foreach ($allPoints as $key => [$value,]) {
if ($isRebirth && key_exists($key, $rebirthDegraded)) {
$value *= $rebirthDegraded[$key];
}
$keyText = General::INHERITANCE_KEY[$key][2];
$userLogger->push("{$keyText} 포인트 {$value} 증가", "inheritPoint");
$totalPoint += $value;
}
$totalPoint = Util::toInt($totalPoint);
$userLogger->push("포인트 {$previousPoint} => {$totalPoint}", "inheritPoint");
$userLogger->flush();
$inheritStor->resetValues();
$inheritStor->setValue('previous', [$totalPoint, null]);
return $totalPoint;
}
function updateMaxDomesticCritical(General $general, $score)
{
$maxDomesticCritical = $general->getAuxVar('max_domestic_critical') ?? 0;
$maxDomesticCritical = $general->getAuxVar(InheritanceKey::max_domestic_critical->value) ?? 0;
$maxDomesticCritical += $score / 2;
$general->setAuxVar('max_domestic_critical', $maxDomesticCritical);
$general->setAuxVar(InheritanceKey::max_domestic_critical->value, $maxDomesticCritical);
$oldMaxDomesticCritical = $general->getInheritancePoint('max_domestic_critical');
$oldMaxDomesticCritical = $general->getInheritancePoint(InheritanceKey::max_domestic_critical);
if ($maxDomesticCritical > $oldMaxDomesticCritical) {
$general->setInheritancePoint('max_domestic_critical', $maxDomesticCritical);
$general->setInheritancePoint(InheritanceKey::max_domestic_critical, $maxDomesticCritical);
}
}
+14 -13
View File
@@ -8,11 +8,11 @@ class MapRequest{
public $neutralView;
public $showMe;
function __construct($obj){
$this->serverID = Util::array_get($obj['serverID'], null);
$this->year = Util::array_get($obj['year']);
$this->month = Util::array_get($obj['month']);
$this->aux = Util::array_get($obj['aux'],[]);
$this->neutralView = Util::array_get($obj['neutralView'], false);
$this->serverID = $obj['serverID'] ?? null;
$this->year = $obj['year'] ?? null;
$this->month = $obj['month'] ?? null;
$this->aux = $obj['aux'] ?? [];
$this->neutralView = $obj['neutralView'] ?? false;
$this->showMe = $obj['showMe'];
}
}
@@ -35,7 +35,7 @@ function getHistoryMap($year, $month, ?string $serverID=null){
$map = DB::db()->queryFirstField('SELECT map FROM ng_history WHERE server_id = %s AND year=%i and month=%i',
$serverID,
$year,
$year,
$month);
if(!$map){
@@ -53,7 +53,7 @@ function getWorldMap($req){
if(is_array($req)){
$req = new MapRequest($req);
}
if($req->year && $req->month){
return getHistoryMap($req->year, $req->month, $req->serverID??null);
}
@@ -98,7 +98,7 @@ function getWorldMap($req){
$spyInfo = (object)null;
if($myNation){
$rawSpy = $db->queryFirstField('select `spy` from `nation` where `nation`=%i',
$rawSpy = $db->queryFirstField('select `spy` from `nation` where `nation`=%i',
$myNation);
if(strpos($rawSpy, '|') !== false || is_numeric($rawSpy)){
@@ -123,16 +123,16 @@ function getWorldMap($req){
$nationList = [];
foreach($db->query('select `nation`, `name`, `color`, `capital` from `nation`') as $row){
$nationList[] = [
Util::toInt($row['nation']),
$row['name'],
$row['color'],
Util::toInt($row['nation']),
$row['name'],
$row['color'],
Util::toInt($row['capital'])
];
}
if($myNation){
//굳이 타국 도시에 있는 아국 장수 리스트를 뽑을 이유가 없음. 일단 다 뽑자.
$shownByGeneralList =
$shownByGeneralList =
array_map('\\sammo\\Util::toInt',
$db->queryFirstColumn('select distinct `city` from `general` where `nation` = %i',
$myNation));
@@ -143,7 +143,7 @@ function getWorldMap($req){
$cityList = [];
foreach($db->query('select `city`, `level`, `state`, `nation`, `region`, `supply` from `city`') as $r){
$cityList[] =
$cityList[] =
array_map('\\sammo\\Util::toInt', [$r['city'], $r['level'], $r['state'], $r['nation'], $r['region'], $r['supply']]);
}
@@ -164,6 +164,7 @@ function getWorldMap($req){
'shownByGeneralList' => $shownByGeneralList,
'myCity' => $myCity,
'myNation' => $myNation,
'version' => 0,
'result' => true
];
}
+10 -40
View File
@@ -60,6 +60,10 @@ function chiefTurnTable()
";
}
function templateLimitMsg(string $turntime): string{
return "이미 너무 많은 접속을 하셨습니다. 다음 턴에 다시 시도해주세요. (턴시간: {$turntime})";
}
function displayiActionObjInfo(?iAction $action)
{
if ($action === null) {
@@ -168,7 +172,7 @@ function commandButton(array $opts = [])
$showSecret = false;
$permission = checkSecretPermission($me);
$btnClassForTournament = $opts['btnClass'];
if ($opts['isTournamentActive']) {
if ($opts['isTournamentApplicationOpen']) {
if ($btnClassForTournament != 'dropdown-item') {
$btnClassForTournament = 'toolbarButton2';
}
@@ -231,57 +235,23 @@ function formatLeadershipBonus(int $value): string
return "<font color=cyan>+{$value}</font>";
}
function getNPCColor(int $npc): ?string{
if ($npc == 1) {
return 'skyblue';
}
if ($npc == 4){
return 'deepskyblue';
}
if ($npc == 5){
return 'darkcyan';
}
if ($npc == 6){
return 'mediumaquamarine';
}
if ($npc > 1) {
return 'cyan';
}
return null;
}
function formatName(string $name, int $npc): string
{
$color = getNPCColor($npc);
if($color === null){
return $name;
}
return "<span style='color:{$color}'>$name</span>";
}
function getMapTheme(): string
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$mapTheme = $gameStor->map_theme ?? 'che';
return $mapTheme;
return GameConst::$mapName;
}
function getMapHtml(?string $mapTheme = null)
function getMapHtml(?string $mapName = null)
{
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
if ($mapTheme === null) {
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$mapTheme = $gameStor->map_theme ?? 'che';
if($mapName === null){
$mapName = GameConst::$mapName;
}
return $templates->render('map', [
'mapTheme' => $mapTheme
'mapName' => $mapName
]);
}
+73 -20
View File
@@ -1,17 +1,68 @@
<?php
namespace sammo;
use sammo\Enums\InheritanceKey;
use sammo\Enums\RankColumn;
use Ds\Map;
/**
* 시간 단위로 일어나는 이벤트들에 대한 함수 모음
*/
function processSumInheritPointRank(){
$db = DB::db();
$generals = General::createGeneralObjListFromDB(null, null, 2);
$points = new Map();
$points->allocate(count($generals));
foreach($generals as $general){
$generalID = $general->getID();
$points[$generalID] = 0;
}
foreach(InheritanceKey::cases() as $key){
if($key === InheritanceKey::previous){
continue;
}
$subPoints = InheritancePointManager::getInstance()->getInheritancePointFromAll($generals, $key);
foreach($generals as $general){
$generalID = $general->getID();
$points[$generalID] += $subPoints[$generalID] ?? 0;
}
}
$pointsPairs = [];
foreach($points as $generalID => $point){
$pointsPairs[] = [
'nation_id' => $generals[$generalID]->getNationID(),
'general_id' => $generalID,
'type' => RankColumn::inherit_point_earned_by_merge->value,
'value' => $point,
];
}
//XXX: multiple batch update가 제공되지 않으므로..
$db->delete('rank_data', '`type` = %s', RankColumn::inherit_point_earned_by_merge->value);
$db->insert('rank_data', $pointsPairs);
$db->query(
'UPDATE `rank_data` D SET `value` = (SELECT SUM(`value`) FROM `rank_data` S WHERE S.general_id = D.general_id AND S.`type` IN %ls) WHERE D.`type` = %s',
[RankColumn::inherit_point_earned_by_action->value, RankColumn::inherit_point_earned_by_merge->value],
RankColumn::inherit_point_earned->value
);
$db->query(
'UPDATE `rank_data` D SET `value` = (SELECT `value` FROM `rank_data` S WHERE S.general_id = D.general_id AND S.`type` = %s) WHERE D.`type` = %s',
RankColumn::inherit_point_spent_dynamic->value,
RankColumn::inherit_point_spent->value
);
}
//1월마다 실행
function processSpring() {
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
//인구 증가
popIncrease();
// 1월엔 무조건 내정 1% 감소
$db->update('city',[
'dead'=>0,
@@ -22,6 +73,9 @@ function processSpring() {
'wall'=>$db->sqleval('wall * 0.99'),
],true);
//인구 증가
popIncrease();
// > 10000 유지비 3%, > 1000 유지비 1%
// 유지비 1%
$db->update('general', [
@@ -40,7 +94,7 @@ function processSpring() {
function processGoldIncome() {
$db = DB::db();
$gameStor = new KVStorage($db, 'game_env');
$gameStor = KVStorage::getStorage($db, 'game_env');
[$year, $month] = $gameStor->getValuesAsArray(['year', 'month']);
$adminLog = [];
@@ -100,7 +154,7 @@ function processGoldIncome() {
$generalObj = new General($rawGeneral, null, null, null, $year, $month, false);
$gold = Util::round(getBill($generalObj->getVar('dedication'))*$ratio);
$generalObj->increaseVar('gold', $gold);
$logger = $generalObj->getLogger();
if($generalObj->getVar('officer_level') > 4){
$logger->pushGeneralActionLog($incomeLog, $logger::PLAIN);
@@ -121,9 +175,9 @@ function processGoldIncome() {
function popIncrease() {
$db = DB::db();
$nationList = $db->queryAllLists('SELECT nation,rate_tmp,type FROM nation');
// 인구 및 민심
$db->update('city', [
@@ -138,7 +192,7 @@ function popIncrease() {
foreach($nationList as [$nationID, $taxRate, $nationType]){
$nationTypeObj = buildNationTypeClass($nationType);
$popRatio = (30 - $taxRate)/200; // 20일때 5% 5일때 12.5% 50일때 -10%
$popRatio = $nationTypeObj->onCalcNationalIncome('pop', $popRatio);
@@ -246,7 +300,7 @@ function getGoldIncome(int $nationID, int $nationLevel, float $taxRate, int $cap
}
$cityIncome *= ($taxRate / 20);
return $cityIncome;
}
@@ -290,9 +344,6 @@ function getWarGoldIncome(string $nationType, array $cityList){
function processFall() {
$db = DB::db();
//인구 증가
popIncrease();
// 7월엔 무조건 내정 1% 감소
$db->update('city',[
'dead'=>0,
@@ -303,6 +354,8 @@ function processFall() {
'wall'=>$db->sqleval('wall * 0.99'),
],true);
//인구 증가
popIncrease();
// > 10000 유지비 3%, > 1000 유지비 1%
// 유지비 1%
@@ -378,7 +431,7 @@ function processRiceIncome() {
$generalObj = new General($rawGeneral, null, null, null, $year, $month, false);
$rice = Util::round(getBill($generalObj->getVar('dedication'))*$ratio);
$generalObj->increaseVar('rice', $rice);
$logger = $generalObj->getLogger();
if($generalObj->getVar('officer_level') > 4){
$logger->pushGeneralActionLog($incomeLog, $logger::PLAIN);
@@ -418,7 +471,7 @@ function getRiceIncome(int $nationID, int $nationLevel, float $taxRate, int $cap
}
$cityIncome *= ($taxRate / 20);
return $cityIncome;
}
@@ -439,12 +492,12 @@ function getWallIncome(int $nationID, int $nationLevel, float $taxRate, int $cap
$cityIncome = 0;
foreach($cityList as $rawCity){
$cityID = $rawCity['city'];
$cityIncome += calcCityWallRiceIncome($rawCity, $officersCnt[$cityID]??0, $capitalID == $cityID, $nationLevel, $nationTypeObj);
}
$cityIncome *= ($taxRate / 20);
return $cityIncome;
}
@@ -520,7 +573,7 @@ function disaster() {
}
else {
$raiseProp = 0.06 - ($city['secu'] / $city['secu_max']) * 0.05; // 1 ~ 6%
}
}
if(Util::randBool($raiseProp)) {
$targetCityList[] = $city;
@@ -592,11 +645,11 @@ function disaster() {
'def'=>$db->sqleval('def * %d', $affectRatio),
'wall'=>$db->sqleval('wall * %d', $affectRatio),
], 'city = %i', $city['city']);
$generalList = array_map(
function($rawGeneral) use ($city, $year, $month){
return new General($rawGeneral, null, $city, null, $year, $month, false);
},
},
$generalListByCity[$city['city']]??[]
);
@@ -619,7 +672,7 @@ function disaster() {
'wall'=>$db->sqleval('least(wall * %d, wall_max)', $affectRatio),
], 'city = %i', $city['city']);
}
}
+209 -604
View File
@@ -2,13 +2,15 @@
namespace sammo;
use sammo\DTO\BettingInfo;
use sammo\Enums\InheritanceKey;
function processTournament()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['tournament', 'phase', 'tnmt_type', 'tnmt_auto', 'tnmt_time']);
$admin = $gameStor->getValues(['tournament', 'phase', 'tnmt_type', 'tnmt_auto', 'tnmt_time', 'last_tournament_betting_id']);
$now = new \DateTime();
$offset = $now->getTimestamp() - (new \DateTime($admin['tnmt_time']))->getTimestamp();
@@ -26,30 +28,17 @@ function processTournament()
}
//현시간이 스탬프 지나친경우
switch ($admin['tnmt_auto']) {
case 1:
$unit = 720;
break;
case 2:
$unit = 420;
break;
case 3:
$unit = 180;
break;
case 4:
$unit = 60;
break;
case 5:
$unit = 30;
break;
case 6:
$unit = 15;
break;
case 7:
$unit = 5;
break;
default:
throw new MustNotBeReachedException();
$unit = [
1 => 720,
2 => 420,
3 => 180,
4 => 60,
5 => 30,
6 => 15,
7 => 5,
][$admin['tnmt_auto']] ?? null;
if($unit === null){
throw new MustNotBeReachedException();
}
//업데이트 횟수
@@ -90,9 +79,12 @@ function processTournament()
final16set();
$tnmt = 6;
$phase = 0;
startBetting();
startBetting($type, $unit);
break;
case 6: //베팅중
$bettingID = $admin['last_tournament_betting_id'];
$betting = new Betting($bettingID);
$betting->closeBetting();
$tnmt = 7;
$phase = 0;
break;
@@ -164,41 +156,42 @@ function processTournament()
$gameStor->tnmt_time = (new \DateTimeImmutable($admin['tnmt_time']))->add(new \DateInterval("PT{$second}S"))->format('Y-m-d H:i:s');
}
function getTournamentTerm(): ?int{
function getTournamentTerm(): ?int
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$tnmt_auto = $gameStor->tnmt_auto;
if($tnmt_auto === null){
if ($tnmt_auto === null) {
$tnmt_auto = $gameStor->tnmt_trig;
}
switch($tnmt_auto){
case 0: return null;
case 1: return 12 * 60;
case 2: return 7 * 60;
case 3: return 3 * 60;
case 4: return 1 * 60;
case 5: return 30;
case 6: return 15;
case 7: return 5;
}
return null;
return [
0 => null,
1 => 12 * 60,
2 => 7 * 60,
3 => 3 * 60,
4 => 1 * 60,
5 => 30,
6 => 15,
7 => 5,
][$tnmt_auto] ?? null;
}
function getTournamentTermText()
{
$term = getTournamentTerm();
if($term === null){
if ($term === null) {
return '수동';
}
if($term % 60 === 0){
if ($term % 60 === 0) {
$termMin = intdiv($term, 60);
return "경기당 {$termMin}";
}
if($term > 60){
if ($term > 60) {
$termSec = $term % 60;
$termMin = intdiv($term, 60);
return "경기당 {$termMin}{$termSec}";
@@ -263,12 +256,12 @@ function getTournament(int $tnmt)
][$tnmt] ?? "TOURNAMENT_TYPE_ERR_{$tnmt}";
}
function printRow($k, $npc, $name, $abil, $tgame, $win, $draw, $lose, $gd, $gl, $prmt)
function printRow(int $k, int $npc, string $name, $abil, $tgame, $win, $draw, $lose, $gd, $gl, $prmt)
{
$k += 1;
if ($prmt > 0) {
$name = "<font color=orange>" . $name . "</font>";
} else if($npc > 0){
} else if ($npc > 0) {
$name = formatName($name, $npc);
}
echo "<tr align=center><td class='bg2'>$k</td><td style='font-size:80%;'>$name</td><td>$abil</td><td>$tgame</td><td>$win</td><td>$draw</td><td>$lose</td><td>$gd</td><td>$gl</td></tr>";
@@ -334,32 +327,15 @@ function startTournament($auto, $type)
eraseTnmtFightLogAll();
switch ($auto) {
case 1:
$unit = 60;
break;
case 2:
$unit = 60;
break;
case 3:
$unit = 60;
break;
case 4:
$unit = 60;
break;
case 5:
$unit = 30;
break;
case 6:
$unit = 15;
break;
case 7:
$unit = 5;
break;
default:
$unit = 60;
break;
}
$unit = [
1 => 60,
2 => 60,
3 => 60,
4 => 60,
5 => 30,
6 => 15,
7 => 5,
][$auto] ?? 60;
$admin = $gameStor->getValues(['year', 'month']);
@@ -367,29 +343,12 @@ function startTournament($auto, $type)
$gameStor->tnmt_time = (new \DateTimeImmutable())->add(new \DateInterval("PT{$unit}M"))->format('Y-m-d H:i:s');
$gameStor->tournament = 1;
$gameStor->tnmt_type = $type;
$gameStor->last_tournament_betting_id = 0;
$gameStor->phase = 0;
$db->update('general', [
'tournament' => 0,
], true);
$db->update('betting', [
'bet0' => 0,
'bet1' => 0,
'bet2' => 0,
'bet3' => 0,
'bet4' => 0,
'bet5' => 0,
'bet6' => 0,
'bet7' => 0,
'bet8' => 0,
'bet9' => 0,
'bet10' => 0,
'bet11' => 0,
'bet12' => 0,
'bet13' => 0,
'bet14' => 0,
'bet15' => 0
], true);
$db->query('TRUNCATE TABLE tournament');
$opener = $db->queryFirstField('SELECT `general`.`name` FROM `general` JOIN `nation` ON `general`.`nation` = `nation`.`nation` WHERE `general`.`officer_level` = 12 AND `nation`.`level` = 7 ORDER BY rand() LIMIT 1');
@@ -416,44 +375,90 @@ function startTournament($auto, $type)
pushGlobalHistoryLog($history, $admin['year'], $admin['month']);
}
function startBetting()
function getDummyBettingInfo(string $tnmt_type): BettingInfo
{
return new BettingInfo(
id: 0,
type: 'tournament',
name: $tnmt_type,
finished: true,
selectCnt: 1,
reqInheritancePoint: false,
openYearMonth: 0,
closeYearMonth: 0,
candidates: []
);
}
function startBetting($type, $unit)
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
[$year, $month, $startyear] = $gameStor->getValuesAsArray(['year', 'month', 'startyear']);
[$year, $month, $startyear, $turnterm] = $gameStor->getValuesAsArray(['year', 'month', 'startyear', 'turnterm']);
pushGlobalHistoryLog([
"<S>◆</>{$year}{$month}월:<B><b>【대회】</b></>우승자를 예상하는 <C>내기</>가 진행중입니다! 호사가의 참여를 기다립니다!"
], $year, $month);
[$typeText, $statName, $statKey] = [
['전력전', '종능', 'total'],
['통솔전', '통솔', 'leadership'],
['일기토', '무력', 'strength'],
['설전', '지력', 'intel'],
][$type];
$bettingID = Betting::genNextBettingID();
//어차피 강제로 닫을 것이므로 크게 신경쓰지 않는다.
$openYearMonth = Util::joinYearMonth($year, $month);
$closeYearMonth = $openYearMonth + 120;
/** @var \sammo\DTO\SelectItem[] */
$candidates = [];
$generalList = $db->query('SELECT no,npc,name,win,leadership,strength,intel,leadership+strength+intel as total from tournament where grp>=20 order by grp, grp_no LIMIT 16');
foreach ($generalList as $idx => $general) {
if ($general['no'] <= 0) {
continue;
}
$general['idx'] = $idx;
$candidates[$general['no']] = new \sammo\DTO\SelectItem(
title: $general['name'],
info: "{$statName}: {$general[$statKey]}",
aux: $general
);
}
$candidateCnt = count($candidates);
Betting::openBetting(new BettingInfo(
id: $bettingID,
type: 'tournament',
name: $typeText,
finished: false,
selectCnt: 1,
reqInheritancePoint: false,
openYearMonth: $openYearMonth,
closeYearMonth: $closeYearMonth,
candidates: $candidates,
));
$betting = new Betting($bettingID);
$gameStor->last_tournament_betting_id = $bettingID;
$betGold = Util::valueFit(floor((3 + $year - $startyear) * 0.334) * 10, 10);
$npcList = $db->queryFirstColumn('SELECT no FROM general WHERE npc >= 2 AND gold >= (500 + %i)', $betGold);
$npcBet = [];
$betSum = [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
$targetList = array_keys($candidates);
foreach ($npcList as $npcID) {
$target = Util::randRangeInt(0, 15);
$betSum[$target] += $betGold;
$target = Util::choiceRandom($targetList);
$npcBet[] = [$npcID, $target];
}
$db->update('general', [
'gold' => $db->sqleval('gold - %i', $betGold),
], 'no IN %li', $npcList);
foreach ($npcBet as [$npcID, $betTarget]) {
$targetKey = "bet{$betTarget}";
$db->update('betting', [
"bet{$betTarget}" => $db->sqleval('%b + %i', $targetKey, $betGold),
], 'general_id = %i', $npcID);
}
foreach ($betSum as $betTarget => $betSumGold) {
$targetKey = "bet{$betTarget}";
$db->update('betting', [
"bet{$betTarget}" => $db->sqleval('%b + %i', $targetKey, $betSumGold),
], 'general_id = 0');
$betting->bet($npcID, null, [$betTarget], $betGold);
}
}
@@ -512,24 +517,26 @@ function fillLowGenAll($tnmt_type)
};
//자동신청하고, 돈 있고, 아직 참가 안한 장수
/** @var array<array{0:array,1:float}> */
$freeJoinerCandidate = [];
foreach($db->query(
foreach ($db->query(
'SELECT no,npc,name,leadership,strength,intel,explevel,horse,weapon,book from general where tnmt=1 and tournament=0',
) as $gen){
) as $gen) {
$score = $scoringCandFunction($gen);
$freeJoinerCandidate[$gen['no']] = [$gen, $score**1.5];
$freeJoinerCandidate[$gen['no']] = [$gen, $score ** 1.5];
}
$joinersValues = [];
$joinersIdx = [];
foreach(Util::range($toBeFilledCnt) as $_){
if(!$freeJoinerCandidate){
foreach (Util::range($toBeFilledCnt) as $_) {
if (!$freeJoinerCandidate) {
break;
}
$general = Util::choiceRandomUsingWeightPair($freeJoinerCandidate);
/** @var array $general */
unset($freeJoinerCandidate[$general['no']]);
$grpIdx = array_keys($grpCount, min($grpCount))[0];
@@ -581,160 +588,37 @@ function fillLowGenAll($tnmt_type)
//7 8강
//8 4강
//9 결승
function getTwo($tournament, $phase)
/**
* @return array{0:int,1:int}
*/
function getTwo(int $tournament, int $phase): array
{
$cand = [];
switch ($tournament) {
case 2:
//예선
switch ($phase % 28) {
case 0:
$cand[0] = 0;
$cand[1] = 1;
break;
case 1:
$cand[0] = 2;
$cand[1] = 3;
break;
case 2:
$cand[0] = 4;
$cand[1] = 5;
break;
case 3:
$cand[0] = 6;
$cand[1] = 7;
break;
case 4:
$cand[0] = 0;
$cand[1] = 2;
break;
case 5:
$cand[0] = 1;
$cand[1] = 3;
break;
case 6:
$cand[0] = 4;
$cand[1] = 6;
break;
case 7:
$cand[0] = 5;
$cand[1] = 7;
break;
case 8:
$cand[0] = 0;
$cand[1] = 3;
break;
case 9:
$cand[0] = 1;
$cand[1] = 6;
break;
case 10:
$cand[0] = 2;
$cand[1] = 5;
break;
case 11:
$cand[0] = 4;
$cand[1] = 7;
break;
case 12:
$cand[0] = 0;
$cand[1] = 4;
break;
case 13:
$cand[0] = 1;
$cand[1] = 5;
break;
case 14:
$cand[0] = 2;
$cand[1] = 6;
break;
case 15:
$cand[0] = 3;
$cand[1] = 7;
break;
case 16:
$cand[0] = 0;
$cand[1] = 5;
break;
case 17:
$cand[0] = 1;
$cand[1] = 4;
break;
case 18:
$cand[0] = 2;
$cand[1] = 7;
break;
case 19:
$cand[0] = 3;
$cand[1] = 6;
break;
case 20:
$cand[0] = 0;
$cand[1] = 6;
break;
case 21:
$cand[0] = 1;
$cand[1] = 7;
break;
case 22:
$cand[0] = 2;
$cand[1] = 4;
break;
case 23:
$cand[0] = 3;
$cand[1] = 5;
break;
case 24:
$cand[0] = 0;
$cand[1] = 7;
break;
case 25:
$cand[0] = 1;
$cand[1] = 2;
break;
case 26:
$cand[0] = 3;
$cand[1] = 4;
break;
case 27:
$cand[0] = 5;
$cand[1] = 6;
break;
}
$candMap = [
[0, 1], [2, 3], [4, 5], [6, 7],
[0, 2], [1, 3], [4, 6], [5, 7],
[0, 3], [1, 6], [2, 5], [4, 7],
[0, 4], [1, 5], [2, 6], [3, 7],
[0, 5], [1, 4], [2, 7], [3, 6],
[0, 6], [1, 7], [2, 4], [3, 5],
[0, 7], [1, 2], [3, 4], [5, 6],
];
$cand = $candMap[$phase % 28];
if ($phase >= 28) {
$temp = $cand[0];
$cand[0] = $cand[1];
$cand[1] = $temp;
$cand = [$cand[1], $cand[0]];
}
break;
case 4:
//본선
switch ($phase % 6) {
case 0:
$cand[0] = 0;
$cand[1] = 1;
break;
case 1:
$cand[0] = 2;
$cand[1] = 3;
break;
case 2:
$cand[0] = 0;
$cand[1] = 2;
break;
case 3:
$cand[0] = 1;
$cand[1] = 3;
break;
case 4:
$cand[0] = 0;
$cand[1] = 3;
break;
case 5:
$cand[0] = 1;
$cand[1] = 2;
break;
}
$candMap = [
[0, 1], [2, 3],
[0, 2], [1, 3],
[0, 3], [1, 2],
];
$cand = $candMap[$phase % 6];
break;
}
return $cand;
@@ -927,29 +811,14 @@ function finalFight($tnmt_type, $tnmt, $phase, $type)
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
switch ($type) {
case 16:
$offset = 20;
$turn = 7;
$next = 7;
break;
case 8:
$offset = 30;
$turn = 3;
$next = 8;
break;
case 4:
$offset = 40;
$turn = 1;
$next = 9;
break;
case 2:
$offset = 50;
$turn = 0;
$next = 0;
break;
default:
throw new MustNotBeReachedException();
[$offset, $turn, $next] = [
16 => [20, 7, 7],
8 => [30, 3, 8],
4 => [40, 1, 9],
2 => [50, 0, 0],
][$type] ?? [0, 0, 0];
if ($offset === 0) {
throw new MustNotBeReachedException();
}
$grp = $phase + $offset;
@@ -987,29 +856,18 @@ function setGift($tnmt_type, $tnmt, $phase)
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['year', 'month', 'develcost']);
$admin = $gameStor->getValues(['year', 'month', 'develcost', 'last_tournament_betting_id']);
$resultHelper = [];
switch ($tnmt_type) {
case 0:
$tp = "전력전";
$tp2 = "tt";
break;
case 1:
$tp = "통솔전";
$tp2 = "tl";
break;
case 2:
$tp = "일기토";
$tp2 = "ts";
break;
case 3:
$tp = "설전";
$tp2 = "ti";
break;
default:
throw new MustNotBeReachedException();
[$tp, $tp2] = [
0 => ['전력전', 'tt'],
1 => ['통솔전', 'tl'],
2 => ['일기토', 'ts'],
3 => ['설전', 'ti'],
][$tnmt_type] ?? [null, null];
if($tp === null || $tp2 === null){
throw new MustNotBeReachedException();
}
//16강자 명성 돈
@@ -1068,7 +926,7 @@ function setGift($tnmt_type, $tnmt, $phase)
//포상 장수 이름, 금액
$resultHelper[$generalID]['reward'] += $cost;
$resultHelper[$generalID]['msg'] = "<span class='ev_highlight'>4강 진출</span>";
General::createGeneralObjFromDB($generalID)->increaseInheritancePoint('tournament', 10);
General::createGeneralObjFromDB($generalID)->increaseInheritancePoint(InheritanceKey::tournament, 10);
}
//결승자 명성 돈
$cost = $admin['develcost'] * 6;
@@ -1140,39 +998,19 @@ function setGift($tnmt_type, $tnmt, $phase)
$logger = $general['logger'];
$logger->pushGeneralActionLog("<C>{$tp}</> 대회의 {$general['msg']}로 <C>{$rewardText}</>의 <S>상금</>, 약간의 <S>명성</> 획득!", ActionLogger::EVENT_PLAIN);
//TODO: 토너먼트의 다른 값이 모두 sql에 직접 입력하므로 기반을 바꿔야함.
$generalObjList[$generalID]->increaseInheritancePoint('tournament', $general['inheritance_point']);
$generalObjList[$generalID]->increaseInheritancePoint(InheritanceKey::tournament, $general['inheritance_point']);
}
//우승자 번호
$winnerGrp = $resultHelper[$winner['no']]['grp'];
$winnerGrpNo = $resultHelper[$winner['no']]['grp_no'];
$winnerSlot = ($winnerGrp - 20) * 2 + $winnerGrpNo;
//당첨칸에 베팅한 사람들만
$globalBet = $db->queryFirstList('SELECT * FROM betting WHERE general_id = 0');
$globalBet = array_splice($globalBet, -16);
$globalBetTotal = array_sum($globalBet);
$rewardRate = round($globalBetTotal / max($globalBet[$winnerSlot], 1), 2);
$betKey = "bet{$winnerSlot}";
$gambleResult = Util::convertArrayToDict($db->query('SELECT general_id, %b as bet FROM betting WHERE %b > 0 AND general_id > 0', $betKey, $betKey), 'general_id');
foreach (General::createGeneralObjListFromDB(Util::squeezeFromArray($gambleResult, 'general_id'), ['gold', 'npc'], 1) as $gambler) {
$reward = Util::round($gambleResult[$gambler->getID()]['bet'] * $rewardRate);
$gambler->increaseVar('gold', $reward);
if (($gambler->getNPCType() == 0) || ($gambler->getNPCType() == 1 && $gambler->getRankVar('betgold', 0) > 0)) {
$gambler->increaseRankVar('betwingold', $reward);
$gambler->increaseRankVar('betwin', 1);
}
$rewardText = number_format($reward);
$gambler->getLogger()->pushGeneralActionLog("<C>{$tp}</> 대회의 베팅 당첨으로 <C>{$rewardText}</>의 <S>금</> 획득!", ActionLogger::EVENT_PLAIN);
$gambler->applyDB($db);
}
$bettingID = $gameStor->last_tournament_betting_id;
$betting = new Betting($bettingID);
$betting->giveReward([$winner['no']]);
}
function setRefund()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
//16강자 명성 돈
@@ -1183,9 +1021,13 @@ function setRefund()
], 'no IN %li', $generalIDList);
//베팅금 환수
$db->update(['general', [
'gold' => $db->sqleval('gold + (SELECT bet0+bet1+bet2+bet3+bet4+bet5+bet6+bet7+bet8+bet9+bet10+bet11+bet12+bet13+bet14+bet15 FROM betting WHERE general_id = general.no)')
]], true);
$bettingID = $gameStor->last_tournament_betting_id ?? 0;
if ($bettingID != 0) {
$betting = new Betting($bettingID);
if (!$betting->getInfo()->finished) {
$betting->giveReward([-1]);
}
}
//자동진행 끝
$gameStor->tnmt_auto = 0;
@@ -1219,19 +1061,15 @@ function fight($tnmt_type, $tnmt, $phs, $group, $g1, $g2, $type)
$turn = 100;
}
[$tp, $tp2] = [
0 => ['total', 'tt'],
1 => ['leadership', 'tl'],
2 => ['strength', 'ts'],
3 => ['intel', 'ti'],
][$tnmt_type] ?? [null, null];
if ($tnmt_type == 1) {
$tp = "leadership";
$tp2 = "tl";
} elseif ($tnmt_type == 2) {
$tp = "strength";
$tp2 = "ts";
} elseif ($tnmt_type == 3) {
$tp = "intel";
$tp2 = "ti";
} else /*$tnmt_type == 0*/ {
$tp = "total";
$tp2 = "tt";
if($tp === null || $tp2 === null){
throw new MustNotBeReachedException($tnmt_type);
}
$e1 = $energy1 = Util::round($gen1[$tp] * getLog($gen1['lvl'], $gen2['lvl']) * 10);
@@ -1338,303 +1176,70 @@ function fight($tnmt_type, $tnmt, $phs, $group, $g1, $g2, $type)
} // 10~50
$critical1 = 0;
$critical2 = 0;
$crticialSkillMap = [
0 => ['전력', '집중'],
1 => ['봉시진', '어린진'],
2 => ['삼단', '나선'],
3 => ['독설', '논파'],
];
$fatalitySkillMap = [
0 => '압도',
1 => '팔문금쇄진',
2 => '일격 필살',
3 => '모독 욕설'
];
$skillMap = [
0 => ['참격', '집중', '역공', '반격', '선제', '도발'],
1 => ['추행진', '학익진', '장사진', '형액진', '기형진', '구행진'],
2 => ['기합', '기염', '반격', '역공', '삼단', '나선'],
3 => ['논파', '항변', '반론', '반박', '도발', '면박'],
];
//막판 분노
$ratio = rand() % 300;
if ($e1 / 5 > $energy1 && $damage1 > $damage2 && $gen1[$tp] >= $ratio) {
$damage2 *= Util::round((rand() % 301 + 200) / 100); // 200 ~ 500%
$critical1 = 1;
if ($tnmt_type == 0) {
switch (rand() % 2) {
case 0:
$str = "전력";
break;
case 1:
$str = "집중";
break;
}
} elseif ($tnmt_type == 1) {
switch (rand() % 2) {
case 0:
$str = "봉시진";
break;
case 1:
$str = "어린진";
break;
}
} elseif ($tnmt_type == 2) {
switch (rand() % 2) {
case 0:
$str = "삼단";
break;
case 1:
$str = "나선";
break;
}
} elseif ($tnmt_type == 3) {
switch (rand() % 2) {
case 0:
$str = "독설";
break;
case 1:
$str = "논파";
break;
}
}
$str = Util::choiceRandom($crticialSkillMap[$tnmt_type]);
$log[] = "<S>●</> <Y>{$gen1['name']}</>의 분노의 <M>{$str}</> 공격!";
}
$ratio = rand() % 300;
if ($e2 / 5 > $energy2 && $damage2 > $damage1 && $gen2[$tp] >= $ratio) {
$damage1 *= Util::round((rand() % 301 + 200) / 100); // 200 ~ 500%
$critical2 = 1;
if ($tnmt_type == 0) {
switch (rand() % 2) {
case 0:
$str = "전력";
break;
case 1:
$str = "집중";
break;
}
} elseif ($tnmt_type == 1) {
switch (rand() % 2) {
case 0:
$str = "봉시진";
break;
case 1:
$str = "어린진";
break;
}
} elseif ($tnmt_type == 2) {
switch (rand() % 2) {
case 0:
$str = "삼단";
break;
case 1:
$str = "나선";
break;
}
} elseif ($tnmt_type == 3) {
switch (rand() % 2) {
case 0:
$str = "독설";
break;
case 1:
$str = "논파";
break;
}
}
$str = Util::choiceRandom($crticialSkillMap[$tnmt_type]);
$log[] = "<S>●</> <Y>{$gen2['name']}</>의 분노의 <M>{$str}</> 공격!";
}
//1합 승부
if ($phase == 1) {
$ratio = rand() % 400;
if ($gen1[$tp] * 0.9 > $gen2[$tp] && $gen1[$tp] >= $ratio) {
$damage1 = 0;
$damage2 = $e2;
if ($tnmt_type == 0) {
$log[] = "<S>●</> <Y>{$gen1['name']}</>의 <M>압도</>!";
} elseif ($tnmt_type == 1) {
$log[] = "<S>●</> <Y>{$gen1['name']}</>의 <M>팔문금쇄진</>!";
} elseif ($tnmt_type == 2) {
$log[] = "<S>●</> <Y>{$gen1['name']}</>의 <M>일격 필살</>!";
} elseif ($tnmt_type == 3) {
$log[] = "<S>●</> <Y>{$gen1['name']}</>의 <M>모독 욕설</>!";
}
$log[] = "<S>●</> <Y>{$gen1['name']}</>의 <M>{$fatalitySkillMap[$tnmt_type]}</>!";
}
if ($gen2[$tp] * 0.9 > $gen1[$tp] && $gen2[$tp] >= $ratio) {
$damage2 = 0;
$damage1 = $e1;
if ($tnmt_type == 0) {
$log[] = "<S>●</> <Y>{$gen2['name']}</>의 <M>압도</>!";
} elseif ($tnmt_type == 1) {
$log[] = "<S>●</> <Y>{$gen2['name']}</>의 <M>팔문금쇄진</>!";
} elseif ($tnmt_type == 2) {
$log[] = "<S>●</> <Y>{$gen2['name']}</>의 <M>일격 필살</>!";
} elseif ($tnmt_type == 3) {
$log[] = "<S>●</> <Y>{$gen2['name']}</>의 <M>모독 욕설</>!";
}
$log[] = "<S>●</> <Y>{$gen2['name']}</>의 <M>{$fatalitySkillMap[$tnmt_type]}</>!";
}
} else {
$ratio = rand() % 1000;
if ($critical1 == 0 && $gen1[$tp] >= $ratio) {
$damage2 *= Util::randRangeInt(150, 300) / 100; // 150 ~ 300%
$critical1 = 1;
if ($tnmt_type == 0) {
switch (rand() % 6) {
case 0:
$str = "참격";
break;
case 1:
$str = "집중";
break;
case 2:
$str = "역공";
break;
case 3:
$str = "반격";
break;
case 4:
$str = "선제";
break;
case 5:
$str = "도발";
break;
}
} elseif ($tnmt_type == 1) {
switch (rand() % 6) {
case 0:
$str = "추행진";
break;
case 1:
$str = "학익진";
break;
case 2:
$str = "장사진";
break;
case 3:
$str = "형액진";
break;
case 4:
$str = "기형진";
break;
case 5:
$str = "구행진";
break;
}
} elseif ($tnmt_type == 2) {
switch (rand() % 6) {
case 0:
$str = "기합";
break;
case 1:
$str = "기염";
break;
case 2:
$str = "반격";
break;
case 3:
$str = "역공";
break;
case 4:
$str = "삼단";
break;
case 5:
$str = "나선";
break;
}
} elseif ($tnmt_type == 3) {
switch (rand() % 6) {
case 0:
$str = "논파";
break;
case 1:
$str = "항변";
break;
case 2:
$str = "반론";
break;
case 3:
$str = "반박";
break;
case 4:
$str = "도발";
break;
case 5:
$str = "면박";
break;
}
}
$str = Util::choiceRandom($skillMap[$tnmt_type]);
$log[] = "<S>●</> <Y>{$gen1['name']}</>의 <M>{$str}</>!";
}
$ratio = rand() % 1000;
if ($critical2 == 0 && $gen2[$tp] >= $ratio) {
$damage1 *= Util::randRangeInt(150, 300) / 100; // 150 ~ 300%
$critical2 = 1;
if ($tnmt_type == 0) {
switch (rand() % 6) {
case 0:
$str = "참격";
break;
case 1:
$str = "집중";
break;
case 2:
$str = "역공";
break;
case 3:
$str = "반격";
break;
case 4:
$str = "선제";
break;
case 5:
$str = "도발";
break;
}
} elseif ($tnmt_type == 1) {
switch (rand() % 6) {
case 0:
$str = "추행진";
break;
case 1:
$str = "학익진";
break;
case 2:
$str = "장사진";
break;
case 3:
$str = "형액진";
break;
case 4:
$str = "기형진";
break;
case 5:
$str = "구행진";
break;
}
} elseif ($tnmt_type == 2) {
switch (rand() % 6) {
case 0:
$str = "기합";
break;
case 1:
$str = "기염";
break;
case 2:
$str = "반격";
break;
case 3:
$str = "역공";
break;
case 4:
$str = "삼단";
break;
case 5:
$str = "나선";
break;
}
} elseif ($tnmt_type == 3) {
switch (rand() % 6) {
case 0:
$str = "논파";
break;
case 1:
$str = "항변";
break;
case 2:
$str = "반론";
break;
case 3:
$str = "반박";
break;
case 4:
$str = "도발";
break;
case 5:
$str = "면박";
break;
}
}
$str = Util::choiceRandom($skillMap[$tnmt_type]);
$log[] = "<S>●</> <Y>{$gen2['name']}</>의 <M>{$str}</>!";
}
}
BIN
View File
Binary file not shown.
-684
View File
@@ -1,684 +0,0 @@
상성 이름 사진 국가 도시 통 무 지 급 출생 사망 꿈 특기
1, "소제1",1001, 0, "낙양", 20, 11, 48, 0, 168, 190, "유지", "-"); $gencount++;
1, "헌제",1002, 0, "낙양", 17, 13, 61, 0, 170, 250, "안전", "-", "한 왕조는 이대로 끝나는 것인가..."); $gencount++;
999, "사마휘",1003, 0, "양양", 71, 11, 96, 0, 173, 234, "은둔", "신산", "좋지, 좋아~"); $gencount++;
999, "우길",1004, 0, "업", 17, 13, 83, 0, 131, 200, "은둔", "신산"); $gencount++;
999, "화타",1005, 0, "낙양", 53, 25, 70, 0, 151, 220, "은둔", "의술", "아픈 사람들은 모두 내게 오시오. 껄껄껄."); $gencount++;
999, "길평",1006, 0, "허창", 27, 15, 72, 0, 158, 200, "은둔", "의술"); $gencount++;
29, "가규",1007, 0, "낙양", 55, 55, 74, 0, 177, 231, "재간", "-"); $gencount++;
136, "가범",1008, 0, "낙양", 58, 48, 73, 0, 202, 237, "유지", "-"); $gencount++;
49, "가비능",1009, 0, "낙양", 58, 83, 32, 0, 172, 235, "정복", "-"); $gencount++;
31, "가충",1010, 0, "낙양", 50, 25, 87, 0, 217, 282, "출세", "-"); $gencount++;
20, "가후",1011, 0, "낙양", 69, 30, 94, 0, 147, 223, "할거", "귀병"); $gencount++;
73, "간옹",1012, 0, "낙양", 31, 33, 70, 0, 164, 225, "안전", "경작"); $gencount++;
129, "감녕",1013, 0, "낙양", 78, 95, 71, 0, 174, 222, "출세", "무쌍"); $gencount++;
127, "감택",1014, 0, "낙양", 62, 44, 79, 0, 182, 243, "유지", "-"); $gencount++;
60, "강단",1015, 0, "낙양", 41, 73, 43, 0, 168, 230, "재간", "-"); $gencount++;
73, "강유",1016, 0, "낙양", 95, 90, 94, 0, 202, 264, "왕좌", "집중"); $gencount++;
102, "고간",1017, 0, "낙양", 60, 57, 51, 0, 168, 206, "유지", "-"); $gencount++;
27, "고람",1018, 0, "낙양", 72, 67, 59, 0, 159, 201, "출세", "기병"); $gencount++;
69, "고상",1019, 0, "낙양", 41, 40, 38, 0, 194, 252, "재간", "-"); $gencount++;
144, "고순",1020, 0, "낙양", 79, 82, 65, 0, 162, 198, "의협", "기병"); $gencount++;
7, "고승",1021, 0, "낙양", 42, 73, 24, 0, 145, 185, "출세", "-"); $gencount++;
120, "고옹",1022, 0, "낙양", 57, 21, 79, 0, 168, 243, "출세", "-"); $gencount++;
63, "고정",1023, 0, "낙양", 67, 65, 55, 0, 190, 251, "정복", "-"); $gencount++;
53, "고패",1024, 0, "낙양", 53, 56, 28, 0, 170, 212, "유지", "-"); $gencount++;
74, "공도",1025, 0, "낙양", 26, 73, 19, 0, 164, 200, "재간", "-"); $gencount++;
142, "공손강",1026, 0, "낙양", 64, 72, 61, 0, 172, 210, "정복", "-"); $gencount++;
142, "공손공",1027, 0, "낙양", 68, 41, 75, 0, 174, 238, "정복", "-"); $gencount++;
142, "공손도",1028, 0, "낙양", 62, 72, 41, 0, 154, 204, "정복", "기병"); $gencount++;
65, "공손범",1029, 0, "낙양", 61, 67, 61, 0, 158, 199, "출세", "-"); $gencount++;
65, "공손속",1030, 0, "낙양", 60, 76, 41, 0, 176, 199, "정복", "-"); $gencount++;
10, "공손연",1031, 0, "낙양", 74, 79, 64, 0, 205, 238, "패권", "돌격"); $gencount++;
65, "공손월",1032, 0, "낙양", 47, 63, 46, 0, 160, 192, "정복", "-"); $gencount++;
65, "공손찬",1033, 0, "낙양", 61, 87, 67, 0, 152, 199, "패권", "기병"); $gencount++;
43, "공융",1034, 0, "낙양", 63, 48, 85, 0, 153, 208, "왕좌", "경작"); $gencount++;
35, "공주",1035, 0, "낙양", 64, 35, 78, 0, 151, 194, "재간", "-"); $gencount++;
83, "공지",1036, 0, "낙양", 57, 54, 64, 0, 178, 242, "대의", "-"); $gencount++;
26, "곽가",1037, 0, "낙양", 47, 23, 99, 0, 170, 207, "패권", "귀모"); $gencount++;
111, "곽도",1038, 0, "낙양", 63, 67, 81, 0, 155, 205, "재간", "-"); $gencount++;
2, "곽사",1039, 0, "낙양", 58, 67, 31, 0, 146, 197, "패권", "-"); $gencount++;
80, "곽유지",1040, 0, "낙양", 37, 22, 71, 0, 190, 259, "재간", "상재"); $gencount++;
67, "곽익",1041, 0, "낙양", 67, 60, 67, 0, 207, 270, "재간", "-"); $gencount++;
67, "곽준",1042, 0, "낙양", 76, 69, 73, 0, 178, 217, "출세", "-"); $gencount++;
27, "곽혁",1043, 0, "낙양", 40, 29, 80, 0, 187, 228, "안전", "-"); $gencount++;
20, "곽회",1044, 0, "낙양", 77, 75, 71, 0, 187, 255, "정복", "-"); $gencount++;
39, "관구검",1045, 0, "낙양", 72, 68, 77, 0, 202, 255, "대의", "-"); $gencount++;
76, "관색",1046, 0, "낙양", 69, 85, 67, 0, 200, 239, "의협", "징병"); $gencount++;
76, "관우",1047, 0, "낙양", 96, 98, 80, 0, 162, 219, "의협", "위압"); $gencount++;
76, "관이",1048, 0, "낙양", 48, 60, 58, 0, 219, 263, "안전", "-"); $gencount++;
76, "관통",1049, 0, "낙양", 49, 63, 60, 0, 218, 259, "대의", "-"); $gencount++;
76, "관평",1050, 0, "낙양", 77, 80, 70, 0, 186, 219, "의협", "보병"); $gencount++;
7, "관해",1051, 0, "낙양", 66, 90, 35, 0, 160, 193, "출세", "-"); $gencount++;
76, "관흥",1052, 0, "낙양", 69, 84, 72, 0, 199, 234, "의협", "돌격"); $gencount++;
40, "괴량",1053, 0, "낙양", 41, 28, 81, 0, 155, 204, "안전", "신중"); $gencount++;
40, "괴월",1054, 0, "낙양", 26, 30, 84, 0, 157, 214, "유지", "귀병"); $gencount++;
98, "교모",1055, 0, "낙양", 59, 58, 61, 0, 150, 191, "안전", "-"); $gencount++;
98, "교현",1056, 0, "낙양", 50, 18, 60, 0, 158, 210, "재간", "-"); $gencount++;
6, "구역거",1057, 0, "낙양", 51, 72, 49, 0, 152, 193, "안전", "-"); $gencount++;
80, "극정",1058, 0, "낙양", 38, 25, 75, 0, 208, 278, "유지", "-"); $gencount++;
46, "금선",1059, 0, "낙양", 55, 49, 36, 0, 155, 208, "할거", "-"); $gencount++;
62, "금환삼결",1060, 0, "낙양", 46, 76, 17, 0, 192, 225, "출세", "-"); $gencount++;
141, "기령",1061, 0, "낙양", 76, 81, 33, 0, 155, 199, "대의", "무쌍"); $gencount++;
122, "낙통",1062, 0, "낙양", 57, 44, 69, 0, 193, 228, "유지", "-"); $gencount++;
124, "노숙1",1063, 0, "낙양", 90, 42, 94, 0, 172, 217, "왕좌", "상재"); $gencount++;
75, "노식",1064, 0, "낙양", 91, 54, 80, 0, 139, 192, "왕좌", "징병"); $gencount++;
59, "뇌동",1065, 0, "낙양", 70, 77, 45, 0, 172, 218, "출세", "궁병"); $gencount++;
142, "뇌박",1066, 0, "낙양", 54, 54, 33, 0, 157, 206, "유지", "-"); $gencount++;
127, "능조",1067, 0, "낙양", 67, 80, 44, 0, 165, 203, "재간", "공성"); $gencount++;
127, "능통",1068, 0, "낙양", 71, 78, 58, 0, 189, 237, "의협", "궁병"); $gencount++;
64, "단경",1069, 0, "낙양", 68, 61, 68, 0, 156, 199, "정복", "-"); $gencount++;
132, "담웅",1070, 0, "낙양", 52, 77, 19, 0, 188, 221, "출세", "-"); $gencount++;
99, "답둔",1071, 0, "낙양", 59, 71, 31, 0, 158, 207, "유지", "-"); $gencount++;
132, "당자",1072, 0, "낙양", 59, 56, 45, 0, 196, 265, "안전", "-"); $gencount++;
60, "대래동주",1073, 0, "낙양", 40, 65, 24, 0, 195, 249, "안전", "-"); $gencount++;
82, "도겸",1074, 0, "낙양", 51, 32, 61, 0, 132, 194, "할거", "인덕"); $gencount++;
120, "도준",1075, 0, "낙양", 64, 57, 50, 0, 238, 285, "안전", "-"); $gencount++;
73, "동궐",1076, 0, "낙양", 66, 50, 76, 0, 204, 271, "대의", "-"); $gencount++;
62, "동다나",1077, 0, "낙양", 51, 71, 27, 0, 189, 225, "유지", "-"); $gencount++;
2, "동민",1078, 0, "낙양", 52, 65, 49, 0, 149, 192, "안전", "-"); $gencount++;
21, "동소",1079, 0, "낙양", 46, 46, 62, 0, 156, 236, "패권", "-"); $gencount++;
127, "동습",1080, 0, "낙양", 53, 64, 32, 0, 169, 215, "출세", "-"); $gencount++;
89, "동승",1081, 0, "낙양", 75, 66, 65, 0, 154, 200, "왕좌", "-"); $gencount++;
78, "동윤",1082, 0, "낙양", 64, 26, 78, 0, 192, 246, "왕좌", "-"); $gencount++;
2, "동탁",1083, 0, "낙양", 87, 91, 54, 0, 139, 192, "패권", "기병"); $gencount++;
66, "동화",1084, 0, "낙양", 48, 64, 53, 0, 168, 219, "대의", "-"); $gencount++;
32, "두예",1085, 0, "낙양", 88, 80, 84, 0, 222, 284, "정복", "-"); $gencount++;
7, "등무",1086, 0, "낙양", 43, 74, 19, 0, 147, 185, "정복", "-"); $gencount++;
41, "등애",1087, 0, "낙양", 94, 82, 92, 0, 197, 264, "패권", "신산"); $gencount++;
116, "등윤",1088, 0, "낙양", 34, 42, 68, 0, 194, 256, "안전", "-"); $gencount++;
73, "등지",1089, 0, "낙양", 74, 51, 80, 0, 182, 251, "할거", "경작"); $gencount++;
41, "등충",1090, 0, "낙양", 60, 82, 55, 0, 230, 264, "출세", "-"); $gencount++;
54, "등현",1091, 0, "낙양", 65, 59, 61, 0, 188, 248, "출세", "-"); $gencount++;
29, "마균",1092, 0, "낙양", 33, 38, 80, 0, 200, 259, "안전", "-"); $gencount++;
71, "마대",1093, 0, "낙양", 77, 79, 49, 0, 183, 246, "대의", "기병"); $gencount++;
70, "마등",1094, 0, "낙양", 80, 87, 56, 0, 149, 211, "왕좌", "기병"); $gencount++;
80, "마속",1095, 0, "낙양", 73, 64, 82, 0, 190, 228, "패권", "집중"); $gencount++;
77, "마량",1096, 0, "낙양", 57, 25, 87, 0, 187, 225, "왕좌", "-"); $gencount++;
48, "마완",1097, 0, "낙양", 49, 64, 26, 0, 170, 211, "안전", "기병"); $gencount++;
19, "마준",1098, 0, "낙양", 45, 63, 62, 0, 196, 260, "안전", "-"); $gencount++;
71, "마철",1099, 0, "낙양", 71, 60, 31, 0, 179, 211, "대의", "기병"); $gencount++;
70, "마초",1100, 0, "낙양", 78, 97, 40, 0, 176, 226, "대의", "기병"); $gencount++;
131, "마충1",1101, 0, "낙양", 67, 62, 51, 0, 186, 222, "재간", "-"); $gencount++;
69, "마충2",1102, 0, "낙양", 61, 68, 51, 0, 187, 249, "출세", "-"); $gencount++;
71, "마휴",1103, 0, "낙양", 71, 60, 32, 0, 178, 211, "대의", "기병"); $gencount++;
116, "만총",1104, 0, "낙양", 79, 40, 78, 0, 170, 242, "할거", "신중"); $gencount++;
51, "망아장",1105, 0, "낙양", 29, 64, 20, 0, 191, 225, "출세", "-"); $gencount++;
44, "맹달",1106, 0, "낙양", 70, 66, 72, 0, 172, 228, "할거", "귀병"); $gencount++;
60, "맹우",1107, 0, "낙양", 63, 79, 26, 0, 190, 251, "정복", "-"); $gencount++;
60, "맹획",1108, 0, "낙양", 78, 92, 50, 0, 186, 245, "왕좌", "격노"); $gencount++;
29, "모개",1109, 0, "낙양", 46, 56, 56, 0, 161, 216, "대의", "-"); $gencount++;
51, "목록대왕",1110, 0, "낙양", 58, 71, 65, 0, 184, 225, "재간", "척사"); $gencount++;
96, "목순",1111, 0, "낙양", 17, 21, 68, 0, 157, 191, "왕좌", "-"); $gencount++;
43, "무안국",1112, 0, "낙양", 51, 73, 18, 0, 156, 191, "재간", "-"); $gencount++;
28, "문빙",1113, 0, "낙양", 70, 77, 43, 0, 178, 237, "유지", "-"); $gencount++;
38, "문앙",1114, 0, "낙양", 71, 91, 46, 0, 222, 285, "대의", "-"); $gencount++;
102, "문추",1115, 0, "낙양", 72, 94, 25, 0, 161, 200, "출세", "무쌍"); $gencount++;
38, "문흠",1116, 0, "낙양", 76, 77, 43, 0, 200, 258, "대의", "-"); $gencount++;
49, "미당대왕",1117, 0, "낙양", 64, 75, 32, 0, 202, 260, "유지", "-"); $gencount++;
108, "미방",1118, 0, "낙양", 58, 65, 37, 0, 169, 222, "패권", "징병"); $gencount++;
77, "미축",1119, 0, "낙양", 26, 30, 65, 0, 165, 220, "왕좌", "상재"); $gencount++;
94, "반봉",1120, 0, "낙양", 61, 75, 17, 0, 155, 191, "출세", "-"); $gencount++;
44, "반준",1121, 0, "낙양", 41, 21, 67, 0, 174, 239, "안전", "-"); $gencount++;
65, "방덕",1122, 0, "낙양", 76, 90, 67, 0, 170, 219, "의협", "기병"); $gencount++;
73, "방통",1123, 0, "낙양", 86, 41, 97, 0, 179, 214, "패권", "반계"); $gencount++;
65, "방회",1124, 0, "낙양", 25, 33, 59, 0, 205, 272, "안전", "-"); $gencount++;
68, "배원소",1125, 0, "낙양", 45, 69, 33, 0, 169, 200, "재간", "-"); $gencount++;
78, "번건",1126, 0, "낙양", 28, 31, 68, 0, 205, 270, "대의", "-"); $gencount++;
149, "번주",1127, 0, "낙양", 67, 77, 21, 0, 149, 192, "할거", "-"); $gencount++;
72, "법정",1128, 0, "낙양", 81, 29, 93, 0, 176, 220, "패권", "신산"); $gencount++;
8, "변희",1129, 0, "낙양", 65, 65, 27, 0, 169, 200, "안전", "-"); $gencount++;
121, "보질",1130, 0, "낙양", 58, 28, 77, 0, 177, 247, "유지", "-"); $gencount++;
113, "복양흥",1131, 0, "낙양", 58, 51, 71, 0, 224, 264, "유지", "-"); $gencount++;
110, "봉기",1132, 0, "낙양", 68, 52, 80, 0, 153, 202, "패권", "집중"); $gencount++;
74, "부동",1133, 0, "낙양", 58, 69, 69, 0, 183, 222, "대의", "-"); $gencount++;
108, "부사인",1134, 0, "낙양", 54, 59, 51, 0, 182, 222, "출세", "-"); $gencount++;
38, "부손",1135, 0, "낙양", 24, 43, 68, 0, 162, 230, "안전", "-"); $gencount++;
74, "부첨",1136, 0, "낙양", 61, 74, 45, 0, 216, 263, "대의", "-"); $gencount++;
66, "비시",1137, 0, "낙양", 18, 36, 61, 0, 176, 240, "재간", "-"); $gencount++;
141, "비연",1138, 0, "낙양", 66, 65, 53, 0, 196, 238, "출세", "-"); $gencount++;
77, "비위",1139, 0, "낙양", 72, 26, 73, 0, 193, 253, "대의", "-"); $gencount++;
144, "사광",1140, 0, "낙양", 57, 49, 66, 0, 175, 235, "안전", "-"); $gencount++;
71, "사마가",1141, 0, "낙양", 61, 85, 18, 0, 167, 222, "정복", "돌격"); $gencount++;
20, "사마랑",1142, 0, "낙양", 25, 32, 63, 0, 171, 217, "대의", "-"); $gencount++;
24, "사마망",1143, 0, "낙양", 71, 61, 65, 0, 205, 271, "정복", "-"); $gencount++;
24, "사마부",1144, 0, "낙양", 55, 31, 73, 0, 180, 272, "대의", "-"); $gencount++;
31, "사마사",1145, 0, "낙양", 87, 64, 91, 0, 208, 255, "정복", "-"); $gencount++;
31, "사마소",1146, 0, "낙양", 93, 63, 84, 0, 211, 265, "정복", "-"); $gencount++;
31, "사마염",1147, 0, "낙양", 92, 78, 72, 0, 236, 290, "패권", "-"); $gencount++;
30, "사마유",1148, 0, "낙양", 62, 45, 79, 0, 248, 283, "왕좌", "-"); $gencount++;
31, "사마의",1149, 0, "낙양", 98, 67, 98, 0, 179, 251, "패권", "반계"); $gencount++;
139, "사섭",1150, 0, "낙양", 63, 61, 71, 0, 137, 226, "안전", "-"); $gencount++;
139, "사일",1151, 0, "낙양", 59, 44, 68, 0, 153, 230, "유지", "-"); $gencount++;
132, "사정",1152, 0, "낙양", 67, 71, 20, 0, 178, 221, "안전", "-"); $gencount++;
146, "사지",1153, 0, "낙양", 61, 49, 70, 0, 163, 227, "안전", "-"); $gencount++;
144, "사휘",1154, 0, "낙양", 67, 71, 61, 0, 165, 227, "유지", "-"); $gencount++;
35, "서막",1155, 0, "낙양", 56, 41, 72, 0, 171, 249, "유지", "-"); $gencount++;
76, "서서",1156, 0, "낙양", 90, 70, 96, 0, 178, 232, "의협", "귀병"); $gencount++;
124, "서성",1157, 0, "낙양", 83, 76, 83, 0, 177, 234, "대의", "-"); $gencount++;
142, "서영",1158, 0, "낙양", 47, 63, 33, 0, 147, 191, "안전", "-"); $gencount++;
23, "서질",1159, 0, "낙양", 55, 73, 34, 0, 207, 253, "재간", "-"); $gencount++;
23, "서황",1160, 0, "낙양", 79, 89, 68, 0, 165, 228, "의협", "필살"); $gencount++;
32, "석포",1161, 0, "낙양", 71, 63, 59, 0, 214, 272, "정복", "-"); $gencount++;
131, "설영",1162, 0, "낙양", 46, 23, 64, 0, 223, 282, "유지", "-"); $gencount++;
128, "설종",1163, 0, "낙양", 27, 33, 67, 0, 187, 243, "유지", "-"); $gencount++;
69, "성의",1164, 0, "낙양", 45, 64, 22, 0, 168, 211, "재간", "-"); $gencount++;
129, "소비",1165, 0, "낙양", 67, 63, 49, 0, 172, 221, "대의", "-"); $gencount++;
76, "손건",1166, 0, "낙양", 42, 33, 73, 0, 165, 215, "대의", null); $gencount++;
125, "손견",1167, 0, "낙양", 96, 95, 76, 0, 156, 192, "왕좌", "무쌍"); $gencount++;
126, "손광",1168, 0, "낙양", 63, 54, 58, 0, 186, 207, "유지", "-"); $gencount++;
125, "손권",1169, 0, "낙양", 90, 77, 83, 0, 182, 252, "할거", "수비"); $gencount++;
126, "손랑",1170, 0, "낙양", 27, 54, 28, 0, 187, 226, "안전", "-"); $gencount++;
126, "손등",1171, 0, "낙양", 52, 39, 77, 0, 209, 241, "할거", "-"); $gencount++;
125, "손량",1172, 0, "낙양", 24, 23, 79, 0, 243, 260, "할거", "-"); $gencount++;
20, "손례",1173, 0, "낙양", 64, 64, 69, 0, 180, 250, "안전", "-"); $gencount++;
124, "손소",1174, 0, "낙양", 76, 80, 68, 0, 188, 241, "정복", "-"); $gencount++;
130, "손수",1175, 0, "낙양", 67, 57, 59, 0, 235, 299, "안전", "-"); $gencount++;
126, "손유",1176, 0, "낙양", 77, 60, 67, 0, 177, 215, "정복", "-"); $gencount++;
122, "손이",1177, 0, "낙양", 57, 62, 57, 0, 223, 272, "안전", "-"); $gencount++;
126, "손정",1178, 0, "낙양", 59, 56, 62, 0, 160, 206, "유지", "-"); $gencount++;
115, "손준",1179, 0, "낙양", 59, 69, 51, 0, 219, 256, "정복", "-"); $gencount++;
7, "손중",1180, 0, "낙양", 53, 63, 24, 0, 154, 185, "안전", "-"); $gencount++;
125, "손책",1181, 0, "낙양", 96, 96, 78, 0, 175, 200, "패권", "필살"); $gencount++;
115, "손침",1182, 0, "낙양", 49, 71, 40, 0, 231, 258, "패권", "-"); $gencount++;
114, "손호",1183, 0, "낙양", 20, 78, 67, 0, 242, 284, "패권", "-"); $gencount++;
126, "손화",1184, 0, "낙양", 35, 25, 71, 0, 224, 253, "왕좌", "-"); $gencount++;
127, "손환",1185, 0, "낙양", 79, 65, 70, 0, 197, 228, "정복", "-"); $gencount++;
126, "손휴",1186, 0, "낙양", 63, 43, 64, 0, 235, 264, "정복", "-"); $gencount++;
117, "손흠",1187, 0, "낙양", 66, 63, 33, 0, 235, 280, "정복", "-"); $gencount++;
147, "송헌",1188, 0, "낙양", 42, 63, 41, 0, 157, 200, "안전", "-"); $gencount++;
95, "순우경",1189, 0, "낙양", 72, 67, 60, 0, 146, 200, "할거", "-"); $gencount++;
22, "순욱1",1190, 0, "낙양", 54, 29, 97, 0, 163, 212, "왕좌", "집중"); $gencount++;
22, "순유",1191, 0, "낙양", 73, 41, 90, 0, 157, 214, "대의", "신중"); $gencount++;
29, "신비",1192, 0, "낙양", 47, 28, 74, 0, 171, 240, "재간", "-"); $gencount++;
37, "신의",1193, 0, "낙양", 55, 61, 51, 0, 190, 252, "출세", "-"); $gencount++;
37, "신탐",1194, 0, "낙양", 56, 58, 57, 0, 188, 254, "출세", "-"); $gencount++;
85, "신평",1195, 0, "낙양", 68, 51, 75, 0, 165, 204, "왕좌", "-"); $gencount++;
102, "심배",1196, 0, "낙양", 75, 66, 68, 0, 156, 204, "패권", "귀병"); $gencount++;
126, "심영",1197, 0, "낙양", 53, 72, 51, 0, 235, 280, "재간", "-"); $gencount++;
47, "아하소과",1198, 0, "낙양", 53, 75, 15, 0, 204, 253, "안전", "척사"); $gencount++;
62, "아회남",1199, 0, "낙양", 50, 74, 30, 0, 190, 225, "출세", "척사"); $gencount++;
23, "악진",1200, 0, "낙양", 73, 67, 56, 0, 159, 218, "대의", "돌격"); $gencount++;
23, "악침",1201, 0, "낙양", 45, 52, 33, 0, 196, 257, "대의", "-"); $gencount++;
63, "악환",1202, 0, "낙양", 54, 82, 55, 0, 196, 251, "재간", "-"); $gencount++;
102, "안량",1203, 0, "낙양", 73, 93, 36, 0, 160, 200, "출세", "위압"); $gencount++;
14, "양백",1204, 0, "낙양", 55, 54, 53, 0, 171, 214, "안전", "-"); $gencount++;
92, "양봉1",1205, 0, "낙양", 57, 64, 36, 0, 153, 197, "유지", "-"); $gencount++;
91, "양봉2",1206, 0, "낙양", 62, 78, 61, 0, 191, 252, "정복", "-"); $gencount++;
13, "양송",1207, 0, "낙양", 15, 35, 34, 0, 167, 215, "안전", "-"); $gencount++;
43, "양수",1208, 0, "낙양", 18, 31, 91, 0, 175, 219, "재간", "귀병"); $gencount++;
61, "양의",1209, 0, "낙양", 67, 56, 71, 0, 190, 235, "유지", "-"); $gencount++;
141, "양조1",1210, 0, "낙양", 68, 54, 60, 0, 202, 256, "출세", "-"); $gencount++;
9, "양추1",1211, 0, "낙양", 51, 67, 16, 0, 159, 199, "정복", "-"); $gencount++;
31, "양호",1212, 0, "낙양", 91, 69, 80, 0, 221, 278, "패권", "-"); $gencount++;
53, "양회",1213, 0, "낙양", 60, 67, 40, 0, 167, 212, "출세", "-"); $gencount++;
141, "양흥",1214, 0, "낙양", 52, 68, 17, 0, 169, 211, "안전", "-"); $gencount++;
6, "어부라",1215, 0, "낙양", 78, 80, 61, 0, 150, 195, "정복", "-"); $gencount++;
64, "엄강",1216, 0, "낙양", 57, 65, 44, 0, 163, 192, "재간", "-"); $gencount++;
10, "엄백호",1217, 0, "낙양", 48, 68, 30, 0, 150, 197, "할거", "-"); $gencount++;
10, "엄여",1218, 0, "낙양", 35, 66, 24, 0, 153, 197, "할거", "-"); $gencount++;
69, "엄안",1219, 0, "낙양", 72, 84, 67, 0, 151, 222, "왕좌", "-"); $gencount++;
7, "엄정",1220, 0, "낙양", 31, 68, 49, 0, 151, 189, "출세", "-"); $gencount++;
121, "엄준",1221, 0, "낙양", 44, 24, 71, 0, 169, 246, "재간", "-"); $gencount++;
71, "여개",1222, 0, "낙양", 51, 42, 67, 0, 194, 227, "유지", "-"); $gencount++;
29, "여건",1223, 0, "낙양", 44, 68, 29, 0, 173, 238, "출세", "-"); $gencount++;
107, "여광",1224, 0, "낙양", 60, 67, 27, 0, 162, 207, "유지", "-"); $gencount++;
124, "여몽",1225, 0, "낙양", 92, 78, 93, 0, 178, 219, "패권", "궁병"); $gencount++;
123, "여범",1226, 0, "낙양", 43, 34, 71, 0, 169, 228, "할거", "-"); $gencount++;
107, "여상",1227, 0, "낙양", 62, 68, 26, 0, 164, 207, "유지", "-"); $gencount++;
105, "여위황",1228, 0, "낙양", 42, 62, 38, 0, 159, 200, "정복", "-"); $gencount++;
145, "여포",1229, 0, "낙양", 74,100, 29, 0, 156, 198, "패권", "돌격"); $gencount++;
50, "염우",1230, 0, "낙양", 58, 51, 18, 0, 209, 264, "출세", "-"); $gencount++;
40, "염유",1231, 0, "낙양", 59, 75, 51, 0, 168, 227, "출세", "-"); $gencount++;
18, "염포",1232, 0, "낙양", 33, 35, 77, 0, 163, 231, "유지", "-"); $gencount++;
40, "예형",1233, 0, "낙양", 77, 31, 95, 0, 173, 209, "은둔", "통찰"); $gencount++;
133, "오강",1234, 0, "낙양", 47, 37, 61, 0, 216, 275, "안전", "-"); $gencount++;
59, "오란",1235, 0, "낙양", 67, 75, 42, 0, 170, 218, "재간", "-"); $gencount++;
72, "오반",1236, 0, "낙양", 70, 66, 45, 0, 171, 234, "재간", "-"); $gencount++;
128, "오언",1237, 0, "낙양", 71, 60, 52, 0, 235, 297, "재간", "-"); $gencount++;
126, "오연",1238, 0, "낙양", 36, 70, 31, 0, 234, 280, "정복", "-"); $gencount++;
69, "오의",1239, 0, "낙양", 75, 72, 74, 0, 165, 237, "유지", "-"); $gencount++;
19, "오질",1240, 0, "낙양", 43, 37, 69, 0, 177, 230, "출세", "-"); $gencount++;
51, "올돌골",1241, 0, "낙양", 77, 92, 15, 0, 186, 225, "출세", "척사"); $gencount++;
52, "옹개",1242, 0, "낙양", 58, 67, 51, 0, 188, 225, "안전", "-"); $gencount++;
20, "왕경",1243, 0, "낙양", 55, 47, 65, 0, 206, 260, "재간", "-"); $gencount++;
97, "왕광",1244, 0, "낙양", 72, 67, 54, 0, 150, 190, "유지", "-"); $gencount++;
30, "왕기1",1245, 0, "낙양", 76, 62, 70, 0, 190, 261, "유지", "-"); $gencount++;
34, "왕랑",1246, 0, "낙양", 49, 29, 51, 0, 162, 228, "할거", "-"); $gencount++;
57, "왕루",1247, 0, "낙양", 40, 28, 76, 0, 173, 211, "유지", "-"); $gencount++;
76, "왕보",1248, 0, "낙양", 47, 34, 75, 0, 171, 219, "대의", "-"); $gencount++;
86, "왕수",1249, 0, "낙양", 34, 34, 67, 0, 168, 218, "재간", "-"); $gencount++;
26, "왕쌍",1250, 0, "낙양", 58, 89, 15, 0, 195, 228, "정복", "보병"); $gencount++;
46, "왕위",1251, 0, "낙양", 59, 60, 68, 0, 163, 208, "안전", "-"); $gencount++;
92, "왕윤",1252, 0, "낙양", 16, 18, 77, 0, 137, 192, "왕좌", "-"); $gencount++;
40, "왕융",1253, 0, "낙양", 62, 41, 77, 0, 234, 305, "재간", "-"); $gencount++;
32, "왕준",1254, 0, "낙양", 81, 83, 76, 0, 206, 285, "대의", "-"); $gencount++;
30, "왕찬",1255, 0, "낙양", 28, 28, 78, 0, 177, 217, "안전", "-"); $gencount++;
33, "왕창",1256, 0, "낙양", 74, 57, 52, 0, 188, 259, "정복", "-"); $gencount++;
69, "왕평",1257, 0, "낙양", 77, 76, 71, 0, 192, 248, "재간", "-"); $gencount++;
71, "왕항",1258, 0, "낙양", 51, 43, 60, 0, 184, 254, "대의", "-"); $gencount++;
33, "왕혼",1259, 0, "낙양", 69, 32, 59, 0, 223, 297, "정복", "-"); $gencount++;
71, "요립",1260, 0, "낙양", 65, 41, 84, 0, 181, 250, "출세", "-"); $gencount++;
74, "요화",1261, 0, "낙양", 67, 58, 60, 0, 170, 264, "의협", "-"); $gencount++;
22, "우금1",1262, 0, "낙양", 80, 74, 71, 0, 159, 221, "정복", "-"); $gencount++;
27, "우금2",1263, 0, "낙양", 63, 77, 37, 0, 173, 226, "대의", "-"); $gencount++;
122, "우번",1264, 0, "낙양", 23, 42, 73, 0, 164, 233, "유지", "-"); $gencount++;
126, "우전",1265, 0, "낙양", 63, 55, 41, 0, 204, 258, "안전", "-"); $gencount++;
86, "원담",1266, 0, "낙양", 67, 59, 55, 0, 173, 205, "왕좌", "-"); $gencount++;
101, "원상",1267, 0, "낙양", 54, 72, 68, 0, 179, 207, "패권", "-"); $gencount++;
101, "원소",1268, 0, "낙양", 85, 67, 76, 0, 154, 202, "패권", "위압"); $gencount++;
140, "원술",1269, 0, "낙양", 77, 59, 71, 0, 155, 199, "패권", "축성"); $gencount++;
140, "원윤",1270, 0, "낙양", 41, 34, 60, 0, 163, 199, "패권", "-"); $gencount++;
101, "원희",1271, 0, "낙양", 69, 57, 72, 0, 176, 207, "할거", "-"); $gencount++;
131, "위소",1272, 0, "낙양", 39, 24, 82, 0, 204, 273, "재간", "-"); $gencount++;
147, "위속",1273, 0, "낙양", 57, 59, 41, 0, 156, 200, "안전", "-"); $gencount++;
81, "위연",1274, 0, "낙양", 78, 94, 62, 0, 175, 234, "패권", "보병"); $gencount++;
96, "위유",1275, 0, "낙양", 53, 69, 71, 0, 151, 193, "재간", "-"); $gencount++;
76, "유기",1276, 0, "낙양", 57, 19, 73, 0, 174, 209, "왕좌", "-"); $gencount++;
36, "유대",1277, 0, "낙양", 61, 57, 62, 0, 147, 202, "재간", "-"); $gencount++;
134, "유도",1278, 0, "낙양", 35, 33, 68, 0, 168, 214, "재간", "-"); $gencount++;
46, "유벽",1279, 0, "낙양", 63, 71, 23, 0, 168, 210, "출세", "-"); $gencount++;
75, "유봉",1280, 0, "낙양", 60, 65, 62, 0, 188, 220, "출세", "-"); $gencount++;
75, "유비",1281, 0, "낙양", 85, 75, 70, 0, 161, 223, "왕좌", "인덕"); $gencount++;
75, "유선1",1282, 0, "낙양", 24, 17, 21, 0, 207, 271, "대의", "-"); $gencount++;
55, "유순",1283, 0, "낙양", 67, 61, 54, 0, 184, 239, "출세", "-"); $gencount++;
75, "유심",1284, 0, "낙양", 63, 46, 70, 0, 238, 263, "왕좌", "-"); $gencount++;
129, "유약",1285, 0, "낙양", 67, 63, 61, 0, 206, 260, "유지", "-"); $gencount++;
55, "유언",1286, 0, "낙양", 60, 40, 74, 0, 132, 194, "할거", "-"); $gencount++;
27, "유엽",1287, 0, "낙양", 40, 29, 79, 0, 176, 235, "유지", "-"); $gencount++;
11, "유요",1288, 0, "낙양", 23, 22, 48, 0, 156, 195, "안전", "발명"); $gencount++;
96, "유우",1289, 0, "낙양", 68, 34, 72, 0, 145, 193, "왕좌", "-"); $gencount++;
55, "유장",1290, 0, "낙양", 38, 31, 63, 0, 162, 219, "할거", "수비"); $gencount++;
45, "유종",1291, 0, "낙양", 22, 26, 61, 0, 191, 208, "할거", "-"); $gencount++;
56, "유파",1292, 0, "낙양", 47, 32, 70, 0, 186, 222, "대의", "-"); $gencount++;
45, "유표1",1293, 0, "낙양", 71, 57, 71, 0, 142, 208, "할거", "-"); $gencount++;
27, "유표2",1294, 0, "낙양", 76, 55, 71, 0, 173, 229, "안전", "-"); $gencount++;
134, "유현",1295, 0, "낙양", 32, 56, 55, 0, 188, 252, "안전", "-"); $gencount++;
122, "육개",1296, 0, "낙양", 66, 30, 72, 0, 198, 269, "재간", "-"); $gencount++;
122, "육손",1297, 0, "낙양", 98, 68, 98, 0, 183, 245, "왕좌", "귀병"); $gencount++;
121, "육적",1298, 0, "낙양", 44, 29, 73, 0, 187, 219, "안전", "-"); $gencount++;
122, "육항",1299, 0, "낙양", 95, 69, 94, 0, 226, 274, "왕좌", "-"); $gencount++;
38, "윤대목",1300, 0, "낙양", 62, 49, 69, 0, 211, 270, "재간", "-"); $gencount++;
80, "윤묵",1301, 0, "낙양", 19, 28, 73, 0, 183, 239, "대의", "-"); $gencount++;
72, "윤상",1302, 0, "낙양", 30, 32, 42, 0, 194, 260, "대의", "-"); $gencount++;
136, "윤직",1303, 0, "낙양", 44, 58, 63, 0, 197, 237, "재간", "-"); $gencount++;
2, "이각",1304, 0, "낙양", 56, 77, 43, 0, 148, 198, "패권", "-"); $gencount++;
146, "이숙",1305, 0, "낙양", 27, 45, 67, 0, 156, 192, "재간", "-"); $gencount++;
71, "이엄",1306, 0, "낙양", 80, 84, 81, 0, 172, 234, "패권", "-"); $gencount++;
2, "이유",1307, 0, "낙양", 64, 22, 90, 0, 150, 192, "패권", "귀모"); $gencount++;
132, "이이",1308, 0, "낙양", 55, 75, 20, 0, 187, 222, "정복", "-"); $gencount++;
77, "이적",1309, 0, "낙양", 55, 27, 77, 0, 162, 226, "할거", "-"); $gencount++;
22, "이전",1310, 0, "낙양", 75, 68, 82, 0, 174, 216, "왕좌", "-"); $gencount++;
71, "이풍1",1311, 0, "낙양", 59, 56, 62, 0, 206, 260, "재간", "-"); $gencount++;
66, "이회",1312, 0, "낙양", 67, 50, 79, 0, 175, 231, "유지", "-"); $gencount++;
114, "잠혼",1313, 0, "낙양", 15, 16, 44, 0, 239, 280, "할거", "-"); $gencount++;
7, "장각",1314, 0, "낙양", 93, 25, 93, 0, 140, 185, "패권", "환술"); $gencount++;
34, "장간",1315, 0, "낙양", 19, 20, 70, 0, 175, 239, "재간", "-"); $gencount++;
7, "장개",1316, 0, "낙양", 48, 69, 19, 0, 155, 202, "안전", "-"); $gencount++;
122, "장굉",1317, 0, "낙양", 25, 21, 85, 0, 153, 212, "왕좌", "-"); $gencount++;
7, "장량",1318, 0, "낙양", 68, 81, 68, 0, 153, 185, "정복", "환술"); $gencount++;
15, "장로",1319, 0, "낙양", 76, 44, 80, 0, 163, 237, "유지", "축성"); $gencount++;
23, "장료",1320, 0, "낙양", 89, 93, 83, 0, 169, 222, "의협", "견고"); $gencount++;
7, "장보",1321, 0, "낙양", 78, 81, 76, 0, 148, 185, "패권", "환술"); $gencount++;
76, "장비",1322, 0, "낙양", 79, 99, 48, 0, 167, 221, "의협", "무쌍"); $gencount++;
62, "장서",1323, 0, "낙양", 44, 48, 35, 0, 225, 290, "출세", "-"); $gencount++;
120, "장소1",1324, 0, "낙양", 42, 24, 91, 0, 156, 236, "안전", "-"); $gencount++;
78, "장소2",1325, 0, "낙양", 51, 44, 71, 0, 202, 264, "재간", "-"); $gencount++;
72, "장송",1326, 0, "낙양", 49, 28, 93, 0, 170, 212, "할거", "통찰"); $gencount++;
148, "장수",1327, 0, "낙양", 71, 72, 69, 0, 154, 207, "할거", "-"); $gencount++;
145, "장양1",1328, 0, "낙양", 62, 66, 65, 0, 150, 199, "출세", "-"); $gencount++;
8, "장연",1329, 0, "낙양", 78, 66, 47, 0, 153, 210, "안전", "-"); $gencount++;
11, "장영",1330, 0, "낙양", 55, 65, 40, 0, 154, 195, "재간", "-"); $gencount++;
118, "장온",1331, 0, "낙양", 21, 30, 69, 0, 193, 231, "할거", "-"); $gencount++;
78, "장완",1332, 0, "낙양", 70, 55, 86, 0, 188, 246, "할거", "상재"); $gencount++;
15, "장위",1333, 0, "낙양", 65, 70, 29, 0, 172, 215, "대의", "-"); $gencount++;
36, "장윤",1334, 0, "낙양", 67, 59, 60, 0, 163, 208, "정복", "-"); $gencount++;
104, "장의거",1335, 0, "낙양", 68, 59, 34, 0, 159, 205, "대의", "-"); $gencount++;
68, "장익",1336, 0, "낙양", 75, 68, 63, 0, 188, 264, "유지", "-"); $gencount++;
56, "장임",1337, 0, "낙양", 83, 82, 74, 0, 169, 214, "대의", "견고"); $gencount++;
148, "장제1",1338, 0, "낙양", 70, 65, 59, 0, 144, 196, "할거", "-"); $gencount++;
32, "장제2",1339, 0, "낙양", 30, 33, 84, 0, 188, 249, "유지", "-"); $gencount++;
126, "장제3",1340, 0, "낙양", 74, 49, 61, 0, 236, 280, "할거", "-"); $gencount++;
17, "장패",1341, 0, "낙양", 44, 78, 43, 0, 165, 231, "할거", "-"); $gencount++;
76, "장포1",1342, 0, "낙양", 69, 85, 49, 0, 198, 229, "재간", "징병"); $gencount++;
113, "장포2",1343, 0, "낙양", 63, 66, 51, 0, 225, 264, "유지", "-"); $gencount++;
27, "장합",1344, 0, "낙양", 83, 91, 63, 0, 167, 231, "출세", "궁병"); $gencount++;
23, "장호",1345, 0, "낙양", 56, 62, 54, 0, 195, 240, "정복", "-"); $gencount++;
31, "장화",1346, 0, "낙양", 49, 24, 86, 0, 232, 300, "유지", "-"); $gencount++;
48, "장횡",1347, 0, "낙양", 53, 67, 25, 0, 178, 211, "재간", "-"); $gencount++;
141, "장훈",1348, 0, "낙양", 67, 61, 60, 0, 156, 206, "안전", "-"); $gencount++;
120, "장휴",1349, 0, "낙양", 42, 35, 70, 0, 204, 244, "재간", "-"); $gencount++;
126, "장흠",1350, 0, "낙양", 64, 66, 67, 0, 168, 219, "대의", "저격"); $gencount++;
96, "저수",1351, 0, "낙양", 82, 54, 88, 0, 156, 201, "할거", "반계"); $gencount++;
130, "전단",1352, 0, "낙양", 64, 73, 61, 0, 204, 261, "출세", "-"); $gencount++;
42, "전속",1353, 0, "낙양", 66, 57, 49, 0, 218, 272, "안전", "-"); $gencount++;
26, "전위1",1354, 0, "낙양", 61, 96, 34, 0, 160, 197, "의협", "필살"); $gencount++;
130, "전위2",1355, 0, "낙양", 74, 69, 62, 0, 230, 274, "출세", "-"); $gencount++;
128, "전종",1356, 0, "낙양", 79, 77, 74, 0, 183, 249, "패권", "-"); $gencount++;
42, "전주",1357, 0, "낙양", 69, 67, 51, 0, 169, 214, "의협", "-"); $gencount++;
96, "전풍",1358, 0, "낙양", 81, 41, 96, 0, 162, 200, "왕좌", "-"); $gencount++;
24, "정무",1359, 0, "낙양", 54, 38, 74, 0, 201, 265, "출세", "-"); $gencount++;
119, "정병",1360, 0, "낙양", 22, 25, 67, 0, 172, 226, "유지", "-"); $gencount++;
126, "정보",1361, 0, "낙양", 81, 64, 76, 0, 151, 216, "패권", "-"); $gencount++;
123, "정봉1",1362, 0, "낙양", 70, 77, 64, 0, 190, 271, "패권", "-"); $gencount++;
24, "정욱",1363, 0, "낙양", 80, 39, 90, 0, 141, 220, "패권", "신중"); $gencount++;
88, "정원",1364, 0, "낙양", 64, 77, 58, 0, 137, 190, "왕좌", "기병"); $gencount++;
7, "정원지",1365, 0, "낙양", 41, 74, 38, 0, 145, 185, "출세", "-"); $gencount++;
69, "정은",1366, 0, "낙양", 53, 62, 26, 0, 169, 211, "재간", "-"); $gencount++;
121, "제갈각",1367, 0, "낙양", 61, 53, 92, 0, 203, 253, "왕좌", "-"); $gencount++;
76, "제갈균",1368, 0, "낙양", 59, 45, 74, 0, 185, 252, "안전", "상재"); $gencount++;
121, "제갈근",1369, 0, "낙양", 60, 42, 88, 0, 174, 241, "왕좌", "경작"); $gencount++;
76, "제갈량",1370, 0, "낙양", 97, 55,100, 0, 181, 234, "왕좌", "집중"); $gencount++;
76, "제갈상",1371, 0, "낙양", 52, 75, 71, 0, 246, 263, "대의", "-"); $gencount++;
135, "제갈정",1372, 0, "낙양", 56, 57, 54, 0, 241, 300, "안전", "-"); $gencount++;
76, "제갈첨",1373, 0, "낙양", 73, 52, 76, 0, 227, 263, "대의", "-"); $gencount++;
135, "제갈탄",1374, 0, "낙양", 79, 79, 73, 0, 206, 258, "패권", "-"); $gencount++;
76, "조광",1375, 0, "낙양", 65, 67, 54, 0, 210, 263, "재간", "-"); $gencount++;
74, "조루",1376, 0, "낙양", 49, 37, 60, 0, 183, 219, "대의", "-"); $gencount++;
24, "조모",1377, 0, "낙양", 53, 32, 30, 0, 241, 260, "할거", "-"); $gencount++;
127, "조무",1378, 0, "낙양", 71, 68, 71, 0, 155, 191, "의협", "-"); $gencount++;
26, "조방",1379, 0, "낙양", 50, 20, 31, 0, 232, 274, "정복", "-"); $gencount++;
83, "조범",1380, 0, "낙양", 58, 40, 63, 0, 168, 218, "유지", "-"); $gencount++;
26, "조비",1381, 0, "낙양", 72, 69, 75, 0, 187, 226, "패권", "징병"); $gencount++;
19, "조상",1382, 0, "낙양", 68, 62, 31, 0, 207, 249, "패권", "-"); $gencount++;
147, "조성",1383, 0, "낙양", 44, 69, 51, 0, 163, 198, "안전", "-"); $gencount++;
26, "조순",1384, 0, "낙양", 66, 57, 72, 0, 170, 210, "정복", "-"); $gencount++;
25, "조식",1385, 0, "낙양", 19, 19, 90, 0, 192, 232, "왕좌", "귀모"); $gencount++;
25, "조앙",1386, 0, "낙양", 44, 65, 62, 0, 175, 197, "왕좌", "-"); $gencount++;
25, "조예",1387, 0, "낙양", 57, 55, 82, 0, 205, 239, "정복", "-"); $gencount++;
26, "조우",1388, 0, "낙양", 67, 55, 67, 0, 199, 260, "대의", "-"); $gencount++;
76, "조운",1389, 0, "낙양", 95, 98, 87, 0, 168, 229, "왕좌", "무쌍"); $gencount++;
25, "조웅",1390, 0, "낙양", 59, 27, 44, 0, 194, 220, "안전", "-"); $gencount++;
26, "조인",1391, 0, "낙양", 74, 79, 62, 0, 168, 223, "패권", "보병"); $gencount++;
25, "조조",1392, 0, "낙양",100, 80, 95, 0, 155, 220, "패권", "반계"); $gencount++;
26, "조진",1393, 0, "낙양", 82, 67, 65, 0, 185, 231, "정복", "-"); $gencount++;
25, "조창",1394, 0, "낙양", 75, 88, 37, 0, 190, 223, "정복", "돌격"); $gencount++;
76, "조통",1395, 0, "낙양", 65, 64, 55, 0, 209, 260, "재간", "-"); $gencount++;
84, "조표",1396, 0, "낙양", 34, 70, 16, 0, 151, 196, "안전", "-"); $gencount++;
7, "조홍1",1397, 0, "낙양", 52, 66, 42, 0, 156, 185, "유지", "-"); $gencount++;
24, "조홍2",1398, 0, "낙양", 72, 69, 44, 0, 169, 232, "패권", "-"); $gencount++;
26, "조환",1399, 0, "낙양", 34, 24, 42, 0, 246, 302, "정복", "-"); $gencount++;
19, "조훈",1400, 0, "낙양", 67, 63, 30, 0, 212, 249, "출세", "-"); $gencount++;
26, "조휴",1401, 0, "낙양", 75, 71, 70, 0, 174, 228, "패권", "-"); $gencount++;
19, "조희",1402, 0, "낙양", 64, 57, 71, 0, 210, 249, "대의", "-"); $gencount++;
22, "종요",1403, 0, "낙양", 16, 20, 74, 0, 151, 230, "유지", "-"); $gencount++;
20, "종회",1404, 0, "낙양", 84, 58, 93, 0, 225, 264, "패권", "-"); $gencount++;
128, "주거",1405, 0, "낙양", 73, 71, 72, 0, 190, 246, "유지", "-"); $gencount++;
118, "주방",1406, 0, "낙양", 56, 36, 76, 0, 200, 240, "할거", "-"); $gencount++;
126, "주연",1407, 0, "낙양", 73, 72, 51, 0, 182, 249, "할거", "-"); $gencount++;
126, "주유",1408, 0, "낙양", 97, 73, 97, 0, 175, 210, "패권", "신산"); $gencount++;
128, "주이",1409, 0, "낙양", 61, 55, 61, 0, 201, 257, "안전", "-"); $gencount++;
88, "주준",1410, 0, "낙양", 82, 75, 65, 0, 149, 195, "왕좌", "-"); $gencount++;
32, "주지",1411, 0, "낙양", 52, 77, 47, 0, 233, 295, "안전", "-"); $gencount++;
76, "주창",1412, 0, "낙양", 42, 79, 30, 0, 164, 219, "의협", "궁병"); $gencount++;
126, "주치",1413, 0, "낙양", 58, 55, 56, 0, 156, 224, "안전", "-"); $gencount++;
41, "주태1",1414, 0, "낙양", 62, 55, 61, 0, 207, 261, "안전", "-"); $gencount++;
126, "주태2",1415, 0, "낙양", 74, 88, 60, 0, 171, 225, "정복", "필살"); $gencount++;
128, "주환",1416, 0, "낙양", 84, 86, 74, 0, 177, 238, "정복", "-"); $gencount++;
29, "진건",1417, 0, "낙양", 62, 70, 62, 0, 214, 292, "정복", "-"); $gencount++;
29, "진교",1418, 0, "낙양", 21, 25, 67, 0, 175, 237, "유지", "-"); $gencount++;
28, "진군",1419, 0, "낙양", 60, 38, 87, 0, 167, 235, "대의", "-"); $gencount++;
143, "진궁",1420, 0, "낙양", 77, 51, 90, 0, 154, 198, "할거", "신중"); $gencount++;
79, "진규",1421, 0, "낙양", 22, 19, 71, 0, 132, 206, "할거", "-"); $gencount++;
72, "진도",1422, 0, "낙양", 71, 85, 70, 0, 171, 237, "대의", "-"); $gencount++;
79, "진등",1423, 0, "낙양", 64, 62, 71, 0, 169, 207, "할거", "-"); $gencount++;
37, "진림",1424, 0, "낙양", 50, 28, 82, 0, 160, 217, "재간", "-"); $gencount++;
124, "진무",1425, 0, "낙양", 62, 74, 59, 0, 176, 215, "재간", "-"); $gencount++;
66, "진복",1426, 0, "낙양", 36, 27, 76, 0, 160, 226, "재간", "-"); $gencount++;
50, "진수",1427, 0, "낙양", 25, 29, 83, 0, 233, 297, "대의", "-"); $gencount++;
81, "진식",1428, 0, "낙양", 47, 68, 52, 0, 191, 230, "출세", "-"); $gencount++;
79, "진진",1429, 0, "낙양", 58, 38, 64, 0, 170, 235, "재간", "-"); $gencount++;
28, "진태",1430, 0, "낙양", 79, 76, 70, 0, 210, 260, "대의", "-"); $gencount++;
11, "진횡",1431, 0, "낙양", 38, 58, 47, 0, 161, 195, "출세", "-"); $gencount++;
21, "차주",1432, 0, "낙양", 55, 66, 62, 0, 164, 199, "안전", "-"); $gencount++;
11, "착융",1433, 0, "낙양", 62, 59, 21, 0, 161, 194, "출세", "-"); $gencount++;
36, "채모",1434, 0, "낙양", 79, 69, 68, 0, 155, 208, "정복", "궁병"); $gencount++;
36, "채중",1435, 0, "낙양", 58, 43, 55, 0, 168, 208, "출세", "-"); $gencount++;
36, "채화",1436, 0, "낙양", 56, 47, 49, 0, 166, 208, "안전", "-"); $gencount++;
66, "초주",1437, 0, "낙양", 22, 26, 81, 0, 201, 270, "대의", "-"); $gencount++;
20, "최염",1438, 0, "낙양", 43, 54, 67, 0, 162, 216, "대의", "-"); $gencount++;
60, "축융",1439, 0, "낙양", 59, 87, 25, 0, 193, 246, "정복", "척사"); $gencount++;
60, "타사대왕",1440, 0, "낙양", 61, 72, 67, 0, 186, 225, "출세", "척사"); $gencount++;
124, "태사자",1441, 0, "낙양", 71, 97, 65, 0, 166, 209, "대의", "무쌍"); $gencount++;
124, "태사향",1442, 0, "낙양", 51, 69, 50, 0, 189, 246, "재간", "-"); $gencount++;
12, "포륭",1443, 0, "낙양", 53, 74, 20, 0, 174, 208, "안전", "-"); $gencount++;
74, "풍습",1444, 0, "낙양", 36, 64, 44, 0, 182, 222, "재간", "-"); $gencount++;
7, "하의",1445, 0, "낙양", 49, 68, 25, 0, 161, 195, "출세", "-"); $gencount++;
121, "하제",1446, 0, "낙양", 74, 73, 64, 0, 171, 227, "재간", "-"); $gencount++;
90, "하진",1447, 0, "낙양", 49, 69, 37, 0, 135, 189, "왕좌", "-"); $gencount++;
24, "하후덕",1448, 0, "낙양", 67, 64, 39, 0, 178, 218, "출세", "-"); $gencount++;
26, "하후돈",1449, 0, "낙양", 88, 92, 71, 0, 156, 220, "의협", "돌격"); $gencount++;
19, "하후무",1450, 0, "낙양", 38, 33, 37, 0, 201, 259, "안전", "-"); $gencount++;
24, "하후상",1451, 0, "낙양", 67, 62, 71, 0, 181, 225, "출세", "-"); $gencount++;
26, "하후연",1452, 0, "낙양", 79, 90, 58, 0, 162, 219, "패권", "궁병"); $gencount++;
26, "하후위",1453, 0, "낙양", 73, 76, 71, 0, 204, 254, "정복", "-"); $gencount++;
26, "하후은",1454, 0, "낙양", 49, 51, 39, 0, 180, 208, "안전", "-"); $gencount++;
23, "하후패",1455, 0, "낙양", 78, 88, 69, 0, 202, 262, "대의", "-"); $gencount++;
20, "하후현",1456, 0, "낙양", 57, 23, 75, 0, 208, 254, "유지", "-"); $gencount++;
26, "하후혜",1457, 0, "낙양", 76, 66, 78, 0, 206, 242, "정복", "-"); $gencount++;
26, "하후화",1458, 0, "낙양", 77, 61, 80, 0, 207, 265, "정복", "-"); $gencount++;
22, "학소",1459, 0, "낙양", 89, 81, 86, 0, 185, 229, "대의", "견고"); $gencount++;
126, "한당",1460, 0, "낙양", 68, 67, 64, 0, 156, 225, "할거", "-"); $gencount++;
93, "한복",1461, 0, "낙양", 66, 59, 42, 0, 149, 191, "안전", "-"); $gencount++;
8, "한섬",1462, 0, "낙양", 39, 62, 35, 0, 159, 196, "출세", "-"); $gencount++;
48, "한수",1463, 0, "낙양", 66, 76, 77, 0, 142, 215, "대의", "기병"); $gencount++;
40, "한숭",1464, 0, "낙양", 21, 25, 70, 0, 154, 210, "재간", "-"); $gencount++;
7, "한충",1465, 0, "낙양", 41, 66, 29, 0, 151, 185, "안전", "-"); $gencount++;
9, "한현",1466, 0, "낙양", 43, 61, 20, 0, 163, 208, "유지", "-"); $gencount++;
27, "한호",1467, 0, "낙양", 60, 73, 45, 0, 164, 218, "유지", "-"); $gencount++;
79, "향랑",1468, 0, "낙양", 51, 21, 77, 0, 167, 247, "대의", "-"); $gencount++;
79, "향총",1469, 0, "낙양", 76, 42, 73, 0, 195, 240, "왕좌", "-"); $gencount++;
139, "허공",1470, 0, "낙양", 65, 63, 59, 0, 155, 200, "유지", "-"); $gencount++;
21, "허유",1471, 0, "낙양", 47, 47, 57, 0, 155, 204, "재간", "-"); $gencount++;
23, "허의",1472, 0, "낙양", 31, 74, 47, 0, 213, 263, "출세", "-"); $gencount++;
26, "허저",1473, 0, "낙양", 57, 98, 27, 0, 169, 226, "정복", "무쌍"); $gencount++;
87, "허정",1474, 0, "낙양", 18, 29, 74, 0, 152, 222, "재간", "-"); $gencount++;
12, "형도영",1475, 0, "낙양", 49, 78, 23, 0, 174, 208, "출세", "-"); $gencount++;
148, "호거아",1476, 0, "낙양", 35, 76, 61, 0, 164, 206, "안전", "-"); $gencount++;
76, "호반",1477, 0, "낙양", 61, 58, 46, 0, 179, 233, "재간", "-"); $gencount++;
20, "호분",1478, 0, "낙양", 71, 60, 61, 0, 222, 288, "할거", "-"); $gencount++;
27, "호주천",1479, 0, "낙양", 77, 75, 65, 0, 169, 230, "정복", "-"); $gencount++;
20, "호준",1480, 0, "낙양", 67, 60, 46, 0, 200, 256, "재간", "-"); $gencount++;
2, "화웅",1481, 0, "낙양", 68, 88, 24, 0, 155, 191, "출세", "돌격"); $gencount++;
131, "화핵",1482, 0, "낙양", 37, 27, 75, 0, 217, 278, "안전", "-"); $gencount++;
10, "화흠",1483, 0, "낙양", 18, 43, 75, 0, 157, 231, "출세", "-"); $gencount++;
21, "환범",1484, 0, "낙양", 20, 25, 81, 0, 199, 249, "유지", "-"); $gencount++;
127, "황개",1485, 0, "낙양", 78, 85, 69, 0, 154, 218, "왕좌", "징병"); $gencount++;
56, "황권",1486, 0, "낙양", 76, 46, 77, 0, 167, 240, "대의", "-"); $gencount++;
41, "황란",1487, 0, "낙양", 29, 70, 25, 0, 200, 264, "재간", "-"); $gencount++;
88, "황보숭",1488, 0, "낙양", 83, 63, 73, 0, 132, 195, "왕좌", "-"); $gencount++;
72, "황충",1489, 0, "낙양", 84, 94, 67, 0, 148, 222, "왕좌", "궁병"); $gencount++;
50, "황호",1490, 0, "낙양", 15, 17, 48, 0, 226, 263, "안전", "-"); $gencount++;
147, "후성",1491, 0, "낙양", 56, 62, 33, 0, 158, 199, "정복", "-"); $gencount++;
123, "가화",1492, 0, "낙양", 50, 66, 40, 0, 176, 224, "-", "-"); $gencount++;
999, "건석",1493, 0, "낙양", 21, 12, 61, 0, 155, 189, "-", "-"); $gencount++;
999, "견씨",1494, 0, "낙양", 35, 24, 58, 0, 182, 221, "-", "-"); $gencount++;
40, "견홍",1495, 0, "낙양", 76, 72, 66, 0, 224, 272, "-", "-"); $gencount++;
120, "고담",1496, 0, "낙양", 33, 21, 69, 0, 203, 244, "-", "-"); $gencount++;
101, "고유",1497, 0, "낙양", 56, 44, 73, 0, 174, 263, "-", "-"); $gencount++;
132, "곽마",1498, 0, "낙양", 68, 71, 49, 0, 239, 280, "-", "-"); $gencount++;
39, "관구수",1499, 0, "낙양", 58, 63, 35, 0, 206, 265, "-", "-"); $gencount++;
39, "관구전",1500, 0, "낙양", 63, 58, 68, 0, 224, 255, "-", "-"); $gencount++;
999, "관로",1501, 0, "낙양", 62, 21, 75, 0, 191, 256, "-", "-"); $gencount++;
65, "관정",1502, 0, "낙양", 35, 50, 73, 0, 158, 199, "-", "-"); $gencount++;
137, "교수",1503, 0, "낙양", 67, 69, 39, 0, 143, 195, "-", "-"); $gencount++;
33, "구건",1504, 0, "낙양", 43, 56, 69, 0, 239, 272, "-", "-"); $gencount++;
41, "구본",1505, 0, "낙양", 52, 41, 70, 0, 232, 269, "-", "-"); $gencount++;
12, "구성",1506, 0, "낙양", 56, 71, 31, 0, 157, 187, "-", "-"); $gencount++;
21, "국연",1507, 0, "낙양", 52, 21, 71, 0, 160, 219, "-", "-"); $gencount++;
99, "국의",1508, 0, "낙양", 83, 79, 50, 0, 146, 191, "-", "-"); $gencount++;
34, "금의",1509, 0, "낙양", 18, 40, 63, 0, 177, 218, "-", "-"); $gencount++;
76, "나헌",1510, 0, "낙양", 86, 67, 75, 0, 218, 270, "-", "-"); $gencount++;
999, "남두",1511, 0, "낙양", 35, 25, 54, 0, 130, 200, "-", "-"); $gencount++;
54, "냉포",1512, 0, "낙양", 70, 82, 69, 0, 176, 214, "-", "-"); $gencount++;
124, "노숙2",1513, 0, "낙양", 70, 55, 76, 0, 208, 274, "-", "-"); $gencount++;
42, "누규",1514, 0, "낙양", 54, 19, 88, 0, 143, 212, "-", "-"); $gencount++;
6, "누반",1515, 0, "낙양", 65, 76, 39, 0, 178, 207, "-", "-"); $gencount++;
130, "누현",1516, 0, "낙양", 23, 20, 68, 0, 223, 275, "-", "-"); $gencount++;
40, "당균",1517, 0, "낙양", 33, 19, 81, 0, 229, 264, "-", "-"); $gencount++;
32, "당빈",1518, 0, "낙양", 70, 74, 62, 0, 235, 294, "-", "-"); $gencount++;
999, "대교",1519, 0, "낙양", 42, 10, 54, 0, 177, 235, "-", "-"); $gencount++;
28, "대릉",1520, 0, "낙양", 64, 75, 45, 0, 199, 258, "-", "-"); $gencount++;
129, "동조",1521, 0, "낙양", 16, 15, 51, 0, 221, 281, "-", "-"); $gencount++;
114, "등수",1522, 0, "낙양", 35, 20, 44, 0, 228, 288, "-", "-"); $gencount++;
50, "마막",1523, 0, "낙양", 22, 17, 5, 0, 221, 265, "-", "-"); $gencount++;
116, "만욱",1524, 0, "낙양", 20, 18, 66, 0, 240, 272, "-", "-"); $gencount++;
120, "맹종",1525, 0, "낙양", 48, 48, 67, 0, 216, 271, "-", "-"); $gencount++;
38, "문호",1526, 0, "낙양", 65, 74, 45, 0, 227, 279, "-", "-"); $gencount++;
999, "미씨",1527, 0, "낙양", 59, 15, 68, 0, 176, 208, "-", "-"); $gencount++;
39, "반림",1528, 0, "낙양", 66, 79, 8, 0, 168, 225, "-", "-"); $gencount++;
129, "반장",1529, 0, "낙양", 77, 78, 69, 0, 177, 222, "-", "-"); $gencount++;
94, "방열",1530, 0, "낙양", 58, 82, 28, 0, 153, 190, "-", "-"); $gencount++;
55, "방희",1531, 0, "낙양", 59, 38, 69, 0, 153, 218, "-", "-"); $gencount++;
30, "배수",1532, 0, "낙양", 10, 11, 77, 0, 223, 271, "-", "-"); $gencount++;
8, "번능",1533, 0, "낙양", 70, 61, 47, 0, 158, 194, "-", "-"); $gencount++;
999, "번씨",1534, 0, "낙양", 32, 17, 45, 0, 176, 220, "-", "-"); $gencount++;
49, "보도근",1535, 0, "낙양", 64, 73, 50, 0, 170, 233, "-", "-"); $gencount++;
129, "보천",1536, 0, "낙양", 68, 60, 72, 0, 222, 272, "-", "-"); $gencount++;
121, "보협",1537, 0, "낙양", 73, 53, 75, 0, 216, 264, "-", "-"); $gencount++;
28, "부하",1538, 0, "낙양", 44, 36, 85, 0, 209, 255, "-", "-"); $gencount++;
26, "비요",1539, 0, "낙양", 70, 65, 73, 0, 192, 228, "-", "-"); $gencount++;
31, "사마주",1540, 0, "낙양", 63, 53, 62, 0, 227, 283, "-", "-"); $gencount++;
41, "사찬",1541, 0, "낙양", 61, 71, 54, 0, 215, 264, "-", "-"); $gencount++;
128, "설후",1542, 0, "낙양", 16, 14, 71, 0, 221, 271, "-", "-"); $gencount++;
36, "성공영",1543, 0, "낙양", 73, 58, 80, 0, 172, 220, "-", "-"); $gencount++;
126, "성만",1544, 0, "낙양", 61, 69, 66, 0, 225, 276, "-", "-"); $gencount++;
999, "소교",1545, 0, "낙양", 57, 23, 66, 0, 178, 218, "-", "-"); $gencount++;
46, "소유",1546, 0, "낙양", 51, 61, 48, 0, 164, 210, "-", "-"); $gencount++;
31, "소제2",1547, 0, "낙양", 22, 16, 78, 0, 224, 268, "-", "-"); $gencount++;
126, "손교",1548, 0, "낙양", 77, 60, 69, 0, 181, 219, "-", "-"); $gencount++;
116, "손기",1549, 0, "낙양", 62, 65, 52, 0, 227, 276, "-", "-"); $gencount++;
999, "손상향",1550, 0, "낙양", 72, 62, 42, 0, 193, 244, "-", "-"); $gencount++;
125, "손익",1551, 0, "낙양", 69, 75, 26, 0, 184, 204, "-", "-"); $gencount++;
125, "손진",1552, 0, "낙양", 64, 71, 48, 0, 234, 280, "-", "-"); $gencount++;
123, "송겸",1553, 0, "낙양", 61, 48, 44, 0, 175, 215, "-", "-"); $gencount++;
85, "순심",1554, 0, "낙양", 20, 21, 79, 0, 164, 208, "-", "-"); $gencount++;
31, "순욱2",1555, 0, "낙양", 10, 16, 77, 0, 225, 289, "-", "-"); $gencount++;
31, "순의",1556, 0, "낙양", 16, 11, 73, 0, 207, 281, "-", "-"); $gencount++;
129, "시삭",1557, 0, "낙양", 36, 66, 44, 0, 226, 268, "-", "-"); $gencount++;
29, "신창",1558, 0, "낙양", 51, 29, 46, 0, 210, 272, "-", "-"); $gencount++;
999, "악신",1559, 0, "낙양", 53, 12, 46, 0, 175, 228, "-", "-"); $gencount++;
138, "악취",1560, 0, "낙양", 56, 68, 58, 0, 157, 195, "-", "-"); $gencount++;
138, "양강",1561, 0, "낙양", 62, 70, 42, 0, 160, 199, "-", "-"); $gencount++;
21, "양부",1562, 0, "낙양", 68, 55, 85, 0, 178, 239, "-", "-"); $gencount++;
72, "양서",1563, 0, "낙양", 56, 62, 66, 0, 198, 260, "-", "-"); $gencount++;
34, "양습",1564, 0, "낙양", 67, 49, 73, 0, 168, 230, "-", "-"); $gencount++;
16, "양앙",1565, 0, "낙양", 65, 70, 39, 0, 172, 215, "-", "-"); $gencount++;
17, "양임",1566, 0, "낙양", 71, 78, 56, 0, 170, 215, "-", "-"); $gencount++;
32, "양제",1567, 0, "낙양", 69, 63, 71, 0, 226, 291, "-", "-"); $gencount++;
33, "양조2",1568, 0, "낙양", 65, 61, 67, 0, 223, 286, "-", "-"); $gencount++;
48, "양추2",1569, 0, "낙양", 66, 67, 61, 0, 172, 238, "-", "-"); $gencount++;
140, "양홍",1570, 0, "낙양", 19, 17, 76, 0, 152, 199, "-", "-"); $gencount++;
31, "양혼",1571, 0, "낙양", 60, 67, 63, 0, 220, 278, "-", "-"); $gencount++;
123, "여거",1572, 0, "낙양", 71, 58, 69, 0, 196, 256, "-", "-"); $gencount++;
130, "여대",1573, 0, "낙양", 83, 72, 70, 0, 161, 256, "-", "-"); $gencount++;
136, "염상",1574, 0, "낙양", 29, 27, 69, 0, 158, 199, "-", "-"); $gencount++;
36, "염행",1575, 0, "낙양", 70, 86, 38, 0, 159, 222, "-", "-"); $gencount++;
73, "영수",1576, 0, "낙양", 69, 70, 74, 0, 234, 264, "-", "-"); $gencount++;
39, "오거",1577, 0, "낙양", 49, 63, 32, 0, 151, 211, "-", "-"); $gencount++;
126, "오경",1578, 0, "낙양", 73, 60, 57, 0, 159, 203, "-", "-"); $gencount++;
999, "오국태",1579, 0, "낙양", 31, 11, 60, 0, 161, 222, "-", "-"); $gencount++;
126, "오찬",1580, 0, "낙양", 69, 41, 78, 0, 181, 245, "-", "-"); $gencount++;
23, "온회",1581, 0, "낙양", 42, 40, 78, 0, 178, 222, "-", "-"); $gencount++;
21, "왕기2",1582, 0, "낙양", 70, 66, 63, 0, 217, 281, "-", "-"); $gencount++;
32, "왕도",1583, 0, "낙양", 48, 44, 70, 0, 210, 269, "-", "-"); $gencount++;
123, "왕돈",1584, 0, "낙양", 60, 65, 41, 0, 198, 256, "-", "-"); $gencount++;
34, "왕릉",1585, 0, "낙양", 73, 60, 71, 0, 172, 251, "-", "-"); $gencount++;
63, "왕문",1586, 0, "낙양", 64, 67, 32, 0, 162, 205, "-", "-"); $gencount++;
32, "왕상",1587, 0, "낙양", 25, 19, 65, 0, 180, 268, "-", "-"); $gencount++;
34, "왕숙",1588, 0, "낙양", 35, 21, 80, 0, 195, 256, "-", "-"); $gencount++;
33, "왕업",1589, 0, "낙양", 32, 6, 46, 0, 220, 280, "-", "-"); $gencount++;
35, "왕충",1590, 0, "낙양", 42, 58, 21, 0, 152, 214, "-", "-"); $gencount++;
1, "우보",1591, 0, "낙양", 43, 63, 12, 0, 159, 192, "-", "-"); $gencount++;
122, "우사",1592, 0, "낙양", 70, 33, 79, 0, 217, 273, "-", "-"); $gencount++;
138, "원요",1593, 0, "낙양", 44, 42, 45, 0, 177, 206, "-", "-"); $gencount++;
95, "원유",1594, 0, "낙양", 57, 38, 73, 0, 150, 193, "-", "-"); $gencount++;
31, "위관",1595, 0, "낙양", 69, 45, 81, 0, 220, 291, "-", "-"); $gencount++;
129, "위막",1596, 0, "낙양", 58, 62, 60, 0, 221, 268, "-", "-"); $gencount++;
55, "유괴",1597, 0, "낙양", 75, 72, 66, 0, 165, 214, "-", "-"); $gencount++;
129, "유략",1598, 0, "낙양", 72, 68, 59, 0, 206, 260, "-", "-"); $gencount++;
45, "유반",1599, 0, "낙양", 74, 79, 48, 0, 168, 210, "-", "-"); $gencount++;
29, "유복",1600, 0, "낙양", 54, 50, 73, 0, 164, 208, "-", "-"); $gencount++;
78, "유선2",1601, 0, "낙양", 9, 21, 39, 0, 224, 264, "-", "-"); $gencount++;
139, "유섭",1602, 0, "낙양", 62, 79, 26, 0, 158, 190, "-", "-"); $gencount++;
28, "유소",1603, 0, "낙양", 66, 51, 73, 0, 195, 264, "-", "-"); $gencount++;
128, "유승",1604, 0, "낙양", 46, 69, 29, 0, 215, 258, "-", "-"); $gencount++;
129, "유찬",1605, 0, "낙양", 74, 75, 66, 0, 172, 255, "-", "-"); $gencount++;
129, "유평",1606, 0, "낙양", 65, 70, 67, 0, 218, 272, "-", "-"); $gencount++;
138, "유훈",1607, 0, "낙양", 51, 64, 50, 0, 163, 216, "-", "-"); $gencount++;
48, "이감",1608, 0, "낙양", 59, 67, 33, 0, 176, 211, "-", "-"); $gencount++;
19, "이승",1609, 0, "낙양", 13, 26, 32, 0, 201, 249, "-", "-"); $gencount++;
22, "이통",1610, 0, "낙양", 75, 84, 52, 0, 168, 211, "-", "-"); $gencount++;
138, "이풍2",1611, 0, "낙양", 72, 77, 50, 0, 158, 199, "-", "-"); $gencount++;
20, "이풍3",1612, 0, "낙양", 23, 25, 71, 0, 204, 254, "-", "-"); $gencount++;
29, "장구",1613, 0, "낙양", 69, 71, 47, 0, 201, 263, "-", "-"); $gencount++;
21, "장기",1614, 0, "낙양", 77, 35, 79, 0, 170, 223, "-", "-"); $gencount++;
74, "장남",1615, 0, "낙양", 71, 64, 38, 0, 187, 222, "-", "-"); $gencount++;
100, "장막",1616, 0, "낙양", 53, 52, 70, 0, 155, 195, "-", "-"); $gencount++;
7, "장만성",1617, 0, "낙양", 73, 83, 47, 0, 143, 184, "-", "-"); $gencount++;
135, "장반",1618, 0, "낙양", 56, 73, 66, 0, 227, 282, "-", "-"); $gencount++;
78, "장빈",1619, 0, "낙양", 30, 28, 67, 0, 216, 263, "-", "-"); $gencount++;
124, "장승",1620, 0, "낙양", 75, 68, 75, 0, 178, 244, "-", "-"); $gencount++;
999, "장양2",1621, 0, "낙양", 58, 50, 47, 0, 130, 184, "-", "-"); $gencount++;
68, "장억",1622, 0, "낙양", 82, 80, 54, 0, 190, 254, "-", "-"); $gencount++;
75, "장준",1623, 0, "낙양", 65, 67, 66, 0, 224, 263, "-", "-"); $gencount++;
20, "장집",1624, 0, "낙양", 31, 27, 74, 0, 196, 254, "-", "-"); $gencount++;
39, "장특",1625, 0, "낙양", 71, 53, 74, 0, 209, 265, "-", "-"); $gencount++;
96, "저곡",1626, 0, "낙양", 57, 53, 67, 0, 184, 204, "-", "-"); $gencount++;
128, "전기",1627, 0, "낙양", 51, 69, 55, 0, 231, 258, "-", "-"); $gencount++;
23, "전만",1628, 0, "낙양", 52, 74, 38, 0, 181, 235, "-", "-"); $gencount++;
128, "전상",1629, 0, "낙양", 5, 6, 11, 0, 208, 258, "-", "-"); $gencount++;
130, "전역",1630, 0, "낙양", 60, 62, 37, 0, 212, 265, "-", "-"); $gencount++;
75, "전예",1631, 0, "낙양", 80, 62, 83, 0, 171, 252, "-", "-"); $gencount++;
64, "전해",1632, 0, "낙양", 71, 63, 57, 0, 154, 199, "-", "-"); $gencount++;
123, "정봉2",1633, 0, "낙양", 67, 68, 52, 0, 198, 266, "-", "-"); $gencount++;
22, "정의",1634, 0, "낙양", 17, 3, 66, 0, 184, 220, "-", "-"); $gencount++;
81, "제갈교",1635, 0, "낙양", 55, 17, 77, 0, 204, 228, "-", "-"); $gencount++;
40, "제갈서",1636, 0, "낙양", 45, 43, 27, 0, 218, 286, "-", "-"); $gencount++;
25, "조충",1637, 0, "낙양", 14, 7, 80, 0, 196, 208, "-", "-"); $gencount++;
121, "종리목",1638, 0, "낙양", 84, 68, 75, 0, 214, 269, "-", "-"); $gencount++;
22, "종육",1639, 0, "낙양", 27, 11, 71, 0, 223, 263, "-", "-"); $gencount++;
122, "좌혁",1640, 0, "낙양", 60, 66, 51, 0, 232, 280, "-", "-"); $gencount++;
36, "주령",1641, 0, "낙양", 77, 70, 69, 0, 170, 236, "-", "-"); $gencount++;
115, "주앙",1642, 0, "낙양", 75, 64, 64, 0, 162, 195, "-", "-"); $gencount++;
52, "주포",1643, 0, "낙양", 59, 72, 12, 0, 191, 225, "-", "-"); $gencount++;
11, "주흔",1644, 0, "낙양", 67, 53, 77, 0, 159, 196, "-", "-"); $gencount++;
140, "진기",1645, 0, "낙양", 58, 67, 46, 0, 165, 198, "-", "-"); $gencount++;
142, "진란",1646, 0, "낙양", 65, 70, 43, 0, 157, 204, "-", "-"); $gencount++;
25, "진랑",1647, 0, "낙양", 57, 70, 38, 0, 192, 234, "-", "-"); $gencount++;
12, "진응",1648, 0, "낙양", 62, 69, 49, 0, 172, 208, "-", "-"); $gencount++;
124, "진표",1649, 0, "낙양", 62, 49, 74, 0, 204, 237, "-", "-"); $gencount++;
999, "채염",1650, 0, "낙양", 40, 22, 64, 0, 168, 237, "-", "-"); $gencount++;
999, "초선",1651, 0, "낙양", 66, 15, 72, 0, 176, 211, "-", "-"); $gencount++;
135, "초이",1652, 0, "낙양", 54, 65, 55, 0, 219, 266, "-", "-"); $gencount++;
65, "추단",1653, 0, "낙양", 63, 71, 36, 0, 148, 193, "-", "-"); $gencount++;
999, "추씨",1654, 0, "낙양", 36, 13, 54, 0, 165, 225, "-", "-"); $gencount++;
71, "추정",1655, 0, "낙양", 67, 65, 66, 0, 144, 193, "-", "-"); $gencount++;
145, "파재",1656, 0, "낙양", 69, 75, 52, 0, 145, 184, "-", "-"); $gencount++;
22, "포신",1657, 0, "낙양", 78, 60, 83, 0, 152, 192, "-", "-"); $gencount++;
114, "하식",1658, 0, "낙양", 18, 38, 29, 0, 230, 284, "-", "-"); $gencount++;
36, "하안",1659, 0, "낙양", 6, 27, 72, 0, 190, 249, "-", "-"); $gencount++;
999, "하후씨",1660, 0, "낙양", 29, 16, 47, 0, 186, 249, "-", "-"); $gencount++;
5, "학맹",1661, 0, "낙양", 57, 66, 41, 0, 156, 197, "-", "-"); $gencount++;
98, "한거자",1662, 0, "낙양", 53, 59, 30, 0, 158, 200, "-", "-"); $gencount++;
19, "한덕",1663, 0, "낙양", 62, 79, 24, 0, 171, 228, "-", "-"); $gencount++;
140, "한윤",1664, 0, "낙양", 27, 24, 68, 0, 155, 197, "-", "-"); $gencount++;
999, "허소",1665, 0, "낙양", 53, 27, 60, 0, 150, 195, "-", "-"); $gencount++;
30, "호열",1666, 0, "낙양", 77, 69, 76, 0, 225, 272, "-", "-"); $gencount++;
76, "호제",1667, 0, "낙양", 58, 42, 68, 0, 207, 264, "-", "-"); $gencount++;
149, "호진",1668, 0, "낙양", 65, 77, 13, 0, 146, 190, "-", "-"); $gencount++;
29, "호질",1669, 0, "낙양", 73, 50, 75, 0, 192, 250, "-", "-"); $gencount++;
7, "환계",1670, 0, "낙양", 12, 25, 67, 0, 156, 221, "-", "-"); $gencount++;
56, "황숭",1671, 0, "낙양", 68, 64, 74, 0, 208, 263, "-", "-"); $gencount++;
999, "황승언",1672, 0, "낙양", 68, 17, 81, 0, 165, 222, "-", "-"); $gencount++;
999, "황월영",1673, 0, "낙양", 58, 14, 75, 0, 186, 235, "-", "-"); $gencount++;
45, "황조",1674, 0, "낙양", 74, 65, 57, 0, 148, 208, "-", "-"); $gencount++;
48, "후선",1675, 0, "낙양", 56, 66, 35, 0, 175, 228, "-", "-"); $gencount++;
8, "휴고",1676, 0, "낙양", 61, 72, 40, 0, 151, 199, "-", "-"); $gencount++;
98, "휴원진",1677, 0, "낙양", 53, 63, 38, 0, 155, 200, "-", "-"); $gencount++;
22, "희지재",1678, 0, "낙양", 24, 5, 86, 0, 157, 194, "-", "-"); $gencount++;
+29 -14
View File
@@ -47,7 +47,7 @@ if ($me['newmsg'] == 1 || $me['newvote'] == 1) {
], 'owner=%i', $userID);
}
$plock = boolval($db->queryFirstField('SELECT plock FROM plock LIMIT 1'));
$plock = boolval($db->queryFirstField('SELECT plock FROM plock WHERE `type`="GAME" LIMIT 1'));
$con = checkLimit($me['con']);
if ($con >= 2) {
@@ -83,12 +83,12 @@ if ($gameStor->npcmode == 0) {
$npcmode = "선택 생성";
}
$color = "cyan";
$mapTheme = $gameStor->map_theme;
$serverName = UniqueConst::$serverName;
$serverCnt = $gameStor->server_cnt;
$auctionCount = $db->queryFirstField('SELECT count(`no`) FROM auction');
$isTournamentActive = $gameStor->tournament == 1;
$isTournamentActive = $gameStor->tournament > 0;
$isTournamentApplicationOpen = $gameStor->tournament == 1;
$isBettingActive = $gameStor->tournament == 6;
$myNationStatic = getNationStaticInfo($generalObj->getNationID());
@@ -125,19 +125,34 @@ if (!$otherTextInfo) {
<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::printStaticValues([
//deprecated, staticValues를 이용할 것
'serverName' => $serverName,
'serverCnt' => $serverCnt,
'serverNick' => DB::prefix(),
'serverID' => UniqueConst::$serverID,
'maxTurn' => GameConst::$maxTurn,
'maxPushTurn' => 12,
'commandList' => getCommandTable($generalObj),
'serverNow' => TimeUtil::now(false),
'baseColor2' => GameConst::$basecolor2,
'lastExecuted' => $gameStor->turntime,
'isLocked' => $plock,
'isTournamentActive' => $isTournamentActive,
'isBettingActive' => $isBettingActive
'isBettingActive' => $isBettingActive,
'staticValues' => [
'serverName' => $serverName,
'serverCnt' => $serverCnt,
'serverNick' => DB::prefix(),
'serverID' => UniqueConst::$serverID,
'maxTurn' => GameConst::$maxTurn,
'maxPushTurn' => 12,
'commandList' => getCommandTable($generalObj),
'serverNow' => TimeUtil::now(false),
'lastExecuted' => $gameStor->turntime,
'isLocked' => $plock,
'isTournamentActive' => $isTournamentActive,
'isBettingActive' => $isBettingActive,
'mapName' => GameConst::$mapName,
'unitSet' => GameConst::$unitSet,
]
]) ?>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
</head>
@@ -174,11 +189,11 @@ if (!$otherTextInfo) {
<div class="s-border-t col py-2 col-4 col-md-2">턴당 갱신횟수 : <?= $gameStor->conlimit ?>회</div>
<div class="s-border-t col py-2 col-8 col-md-4"><?= info(3) ?></div>
<div class="s-border-t py-2 col col-6 col-md-4">
<?php if ($isTournamentActive) : ?>
↑<span style='color:cyan'><?=(['전력전', '통솔전', '일기토', '설전',])[$gameStor->tnmt_type] ?? '' ?> <?= getTournament($gameStor->tournament) ?> <?= getTournamentTime() ?></span>↑
<?php else : ?>
<span style='color:magenta'>현재 토너먼트 경기 없음</span>
<?php endif; ?>
<?php if ($isTournamentActive) : ?>
↑<span style='color:cyan'><?= (['전력전', '통솔전', '일기토', '설전',])[$gameStor->tnmt_type] ?? '' ?> <?= getTournament($gameStor->tournament) ?> <?= getTournamentTime() ?></span>↑
<?php else : ?>
<span style='color:magenta'>현재 토너먼트 경기 없음</span>
<?php endif; ?>
</div>
<div class="s-border-t py-2 col col-6 col-md-2">
<div style="display:inline-block;"><?= $plock ? ("<span style='color:magenta;'>동작 시각: " . substr($gameStor->turntime, 5, 14) . "</span>") : ("<span style='color:cyan;'>동작 시각: " . substr($gameStor->turntime, 5, 14) . "</span>") ?></div>
@@ -241,7 +256,7 @@ if (!$otherTextInfo) {
</div>
<?php endif; ?>
<div id="map_view" class="gx-0">
<div id="mapZone" class="view-item"><?= getMapHtml($mapTheme) ?></div>
<div id="mapZone" class="view-item"><?= getMapHtml() ?></div>
<div class="view-item" id="reservedCommandZone">
<div id="reservedCommandList"></div>
<div id="actionMiniPlate" class="gx-0 row">
@@ -257,7 +272,7 @@ if (!$otherTextInfo) {
<div id="nation-position"><?php myNationInfo($generalObj); ?></div>
<div id="general-position"><?php generalInfo($generalObj); ?></div>
<div id="generalCommandButton" class="row gx-0">
<div class="buttonPlate bg2"><?= commandButton(['btnClass' => 'btn btn-sammo-nation', 'isTournamentActive' => $isTournamentActive, 'isBettingActive' => $isBettingActive]) ?></div>
<div class="buttonPlate bg2"><?= commandButton(['btnClass' => 'btn btn-sammo-nation', 'isTournamentApplicationOpen' => $isTournamentApplicationOpen, 'isBettingActive' => $isBettingActive]) ?></div>
</div>
</div>
</div>
@@ -357,7 +372,7 @@ if (!$otherTextInfo) {
국가 메뉴
</div>
<ul class="dropdown-menu" aria-labelledby="navbarNation" id="navbarNationItems">
<?= commandButton(['btnBegin' => '<li>', 'btnEnd' => '</li>', 'btnClass' => 'dropdown-item', 'isTournamentActive' => $isTournamentActive, 'isBettingActive' => $isBettingActive]) ?>
<?= commandButton(['btnBegin' => '<li>', 'btnEnd' => '</li>', 'btnClass' => 'dropdown-item', 'isTournamentApplicationOpen' => $isTournamentApplicationOpen, 'isBettingActive' => $isBettingActive]) ?>
</ul>
</li>
<li class="nav-item dropup">
-76
View File
@@ -1,76 +0,0 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$betTarget = Util::getPost('target', 'int', -1);
$betGold = Util::getPost('amount', 'int', 0);
if($betTarget < 0 || $betTarget >= 16 || $betGold < 10 || $betGold > 1000){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 입력입니다'
]);
}
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$generalID = $session->generalID;
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
increaseRefresh("베팅", 1);
$tournament = $gameStor->tournament;
if($tournament != 6) {
Json::die([
'result'=>false,
'reason'=>'베팅 기간이 아닙니다.'
]);
}
$myGold = $db->queryFirstField('SELECT gold FROM general WHERE no = %i', $generalID);
$bets = $db->queryFirstList('SELECT * FROM betting WHERE general_id = %i', $generalID);
$bets = array_splice($bets, -16);
$totalBet = array_sum($bets);
$oldBet = $bets[$betTarget];
$targetKey = "bet{$betTarget}";
if($myGold - $betGold < 500){
Json::die([
'result'=>false,
'reason'=>'여유 자금이 부족합니다.'
]);
}
if($betGold + $totalBet > 1000){
Json::die([
'result'=>false,
'reason'=>'베팅 허용 금액을 초과했습니다.'
]);
}
$db->update('betting', [
$targetKey=>$db->sqleval('%b + %i', $targetKey, $betGold),
], 'general_id = %i', $generalID);
$db->update('general', [
'gold'=>$db->sqleval('gold - %i', $betGold),
], 'no = %i', $generalID);
$db->update('rank_data', [
'value'=>$db->sqleval('value + %i', $betGold)
], 'general_id = %i AND type = "betgold"', $generalID);
$db->update('betting', [
$targetKey=>$db->sqleval('%b + %i', $targetKey, $betGold)
], 'general_id = 0');
Json::die([
'result'=>true,
'reason'=>'SUCCESS'
]);
+1 -3
View File
@@ -41,8 +41,6 @@ if ($permission < 4) {
]);
}
$reason = trim($reason);
$letter = $db->queryFirstRow('SELECT * FROM ng_diplomacy WHERE no=%i AND src_nation_id = %i AND state = \'proposed\'', $letterNo, $me['nation']);
if(!$letter){
Json::die([
@@ -66,7 +64,7 @@ $unlimited = new \DateTime('9999-12-31');
$aux['reason'] = [
'who'=>$me['no'],
'action'=>'cancelled',
'reason'=>$reason
'reason'=>'회수',
];
$db->update('ng_diplomacy', [
'state'=>'cancelled',
-109
View File
@@ -1,109 +0,0 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
//로그인 검사
$session = Session::requireLogin([]);
$userID = Session::getUserID();
$db = DB::db();
$withToken = Util::getPost('with_token', 'bool', false);
$gameStor = KVStorage::getStorage($db, 'game_env');
if($session->isGameLoggedIn()){
increaseRefresh("장수일람", 2);
$me = $db->queryFirstRow('SELECT con, turntime FROM general WHERE owner=%i', $userID);
$con = checkLimit($me['con']);
if ($con >= 2) {
Json::die([
'result'=>false,
'reason'=>'접속 제한중입니다. 1턴 이내에 너무 많은 갱신을 하셨습니다.'
]);
}
}
else{
$availableNextCall = $session->availableNextCallGetGeneralList??'2000-01-01 00:00:00';
$now = new \DateTimeImmutable();
if($now <= new \DateTimeImmutable($availableNextCall) && $session->userGrade < 5){
Json::die([
'result'=>false,
'reason'=>"장수 리스트는 10초에 한번 갱신 가능합니다.\n다음 시간 : ".$availableNextCall
]);
}
$availableNextCall = $now->add(new \DateInterval('PT10S'))->format('Y-m-d H:i:s');
$session->availableNextCallGetGeneralList = $availableNextCall;
}
$session->setReadOnly();
$rawGeneralList = $db->queryAllLists('SELECT owner,no,picture,imgsvr,npc,age,nation,special,special2,personal,name,owner_name as ownerName,injury,leadership,strength,intel,experience,dedication,officer_level,killturn,connect from general');
$ownerNameList = [];
if($gameStor->isunited){
foreach(RootDB::db()->queryAllLists('SELECT no, name FROM member') as [$ownerID, $ownerName]){
$ownerNameList[$ownerID] = $ownerName;
}
}
$generalList = [];
foreach($rawGeneralList as $rawGeneral){
[$owner,$no,$picture,$imgsvr,$npc,$age,$nation,$special,$special2,$personal,$name,$ownerName,$injury,$leadership,$strength,$intel,$experience,$dedication,$officerLevel,$killturn,$connectCnt] = $rawGeneral;
if(key_exists($owner, $ownerNameList)){
$ownerName = $ownerNameList[$owner];
}
$nationArr = getNationStaticInfo($nation);
$lbonus = calcLeadershipBonus($officerLevel, $nationArr['level']);
$generalList[] = [
$no,
$picture,
$imgsvr,
$npc,
$age,
$nationArr['name'],
getGeneralSpecialDomesticName($special),
getGeneralSpecialWarName($special2),
getGenChar($personal),
$name,
$npc==1?$ownerName:null,
$injury,
$leadership,
$lbonus,
$strength,
$intel,
getExpLevel($experience),
getHonor($experience),
getDed($dedication),
getOfficerLevelText($officerLevel, $nationArr['level']),
$killturn,
$connectCnt
];
}
$result = [
'result'=>'true',
'list'=>$generalList,
];
if($withToken){
$now = (new \DateTimeImmutable())->format('Y-m-d H:i:s');
$tokens = [];
foreach($db->query('SELECT * FROM select_npc_token WHERE `valid_until`>=%s', $now) as $token){
$validUntil = $token['valid_until'];
foreach(Json::decode($token['pick_result']) as $pickResult){
$tokens[$pickResult['no']]=$pickResult['keepCnt'];
}
}
$result['token'] = $tokens;
}
Json::die($result);
-184
View File
@@ -1,184 +0,0 @@
<?php
namespace sammo;
//통합 세력장수&암행부 viewer
include "lib.php";
include "func.php";
//로그인 검사
$session = Session::requireGameLogin([])->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
$reqType = Util::getReq('req', 'int', 1);
$reqForce = Util::getReq('force', 'bool', false);
$gameStor = KVStorage::getStorage($db, 'game_env');
increaseRefresh("세력장수", 1);
$me = $db->queryFirstRow('SELECT con, turntime, belong, nation, officer_level, permission, penalty FROM general WHERE owner=%i', $userID);
$con = checkLimit($me['con']);
if ($con >= 2) {
Json::die([
'result' => false,
'reason' => '접속 제한중입니다. 1턴 이내에 너무 많은 갱신을 하셨습니다.'
]);
}
$nationID = $me['nation'];
$permission = checkSecretPermission($me, true);
if ($reqForce && $reqType > $permission) {
Json::die([
'result' => false,
'reason' => '권한이 부족합니다.'
]);
}
$permission = min($reqType, $permission);
$nationArr = getNationStaticInfo($nationID);
$viewColumns = [
'no' => 0,
'name' => 0,
'owner_name' => 9,
'nation' => 0,
'city' => 1,
'officer_level' => 2,
'officer_city' => 2,
'npc' => 0,
'defence_train' => 2,
'troop' => 2,
'injury' => 0,
'leadership' => 0,
'strength' => 0,
'intel' => 0,
'experience' => 1,
'explevel' => 0,
'dedication' => 1,
'dedlevel' => 0,
'gold' => 0,
'rice' => 0,
'crewtype' => 2,
'crew' => 2,
'train' => 2,
'atmos' => 2,
'killturn' => 0,
'turntime' => 2,
'picture' => 0,
'imgsvr' => 0,
'age' => 0,
'special' => 0,
'special2' => 0,
'personal' => 0,
'belong' => 0,
'horse' => 2,
'weapon' => 2,
'book' => 2,
'item' => 2,
'connect' => 0
];
$customViewColumns = [
'officerLevel' => 0,
'officerLevelText' => 0,
'lbonus' => 0,
'ownerName' => 0,
'honorText' => 0
];
function getOfficerLevel($rawGeneral)
{
global $permission;
$level = $rawGeneral['officer_level'];
if ($level >= 5) {
return $level;
}
if ($permission > 1) {
return $level;
}
return 1;
}
$specialViewFilter = [
'officerLevel' => function ($rawGeneral){
return getOfficerLevel($rawGeneral);
},
'special' => function ($rawGeneral) {
return getGeneralSpecialDomesticName($rawGeneral['special']);
},
'special2' => function ($rawGeneral) {
return getGeneralSpecialWarName($rawGeneral['special2']);
},
'personal' => function ($rawGeneral) {
return getGenChar($rawGeneral['personal']);
},
'lbonus' => function ($rawGeneral) use ($nationArr) {
return calcLeadershipBonus($rawGeneral['officer_level'], $nationArr['level']);
},
'ownerName' => function ($rawGeneral) {
if ($rawGeneral['npc'] != 1) {
return null;
}
return $rawGeneral['owner_name'];
},
'officerLevelText' => function ($rawGeneral) use ($nationArr) {
$level = getOfficerLevel($rawGeneral);
return getOfficerLevelText($level, $nationArr['level']);
},
'honorText' => function ($rawGeneral) {
return getHonor($rawGeneral['experience']);
},
'dedLevelText' => function ($rawGeneral) {
return getDedLevelText($rawGeneral['dedLevel']);
},
'turntime' => function ($rawGeneral) {
//'0000-00-00 11:23';
return substr($rawGeneral['turntime'], 11, 5);
}
];
[$queryColumns, $rankColumns] = General::mergeQueryColumn(array_keys($viewColumns), 1);
$rawGeneralList = Util::convertArrayToDict($db->query('SELECT %l from general WHERE nation = %i', Util::formatListOfBackticks($queryColumns), $nationID), 'no');
$resultColumns = [];
foreach ($viewColumns as $column => $reqPermission) {
if ($reqPermission > $permission) {
continue;
}
$resultColumns[] = $column;
}
foreach ($customViewColumns as $column => $reqPermission) {
if ($reqPermission > $permission) {
continue;
}
$resultColumns[] = $column;
}
$generalList = [];
foreach ($rawGeneralList as $rawGeneral) {
//General 생성?
$item = [];
foreach ($resultColumns as $column) {
if (key_exists($column, $specialViewFilter)) {
$value = $specialViewFilter[$column]($rawGeneral);
}
else{
$value = $rawGeneral[$column];
}
$item[] = $value;
}
$generalList[] = $item;
}
$result = [
'result' => true,
'column' => $resultColumns,
'list' => $generalList,
];
Json::die($result);
-46
View File
@@ -1,46 +0,0 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
$year = Util::getReq('year', 'int');
$month = Util::getReq('month', 'int');
$serverID = Util::getReq('serverID', 'string', null);
$url = '/a_history.php';
if(!strpos($_SERVER['HTTP_REFERER'], $url)) {
Json::die([
'result'=>false,
'reason'=>'Invalid Referer'
]);
}
if($year === null || !$month) {
Json::die([
'result'=>false,
'reason'=>'year, month가 지정되지 않았습니다'
]);
}
if(!$serverID){
$serverID = UniqueConst::$serverID;
}
//로그인 검사
$session = Session::requireGameLogin([])->setReadOnly();
$db = DB::db();
$map = $db->queryFirstField('SELECT map FROM ng_history WHERE server_id=%s AND year=%i AND month=%i', $serverID, $year, $month);
if(!$map){
Json::die([
'result'=>false,
'reason'=>'해당하는 연월의 지도가 없습니다'
]);
}
Json::die($map, Json::PASS_THROUGH);
+8 -15
View File
@@ -31,17 +31,12 @@ $now = time();
if($mapInfo && ($now - $mapInfo['timestamp'] < 600)){
$mapEtag = $mapInfo['etag'];
$mapModified = $mapInfo['timestamp'];
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $mapModified)." GMT");
header("Etag: $mapEtag");
if (
strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']??'2000-01-01') === $mapModified ||
trim($_SERVER['HTTP_IF_NONE_MATCH']??'') === $mapEtag
) {
header("HTTP/1.1 304 Not Modified");
die();
}
WebUtil::setCacheHeader(new APICacheResult(TimeUtil::secondsToDateTime($mapModified), $mapEtag));
$reqMapEtag = WebUtil::parseETag();
$reqModifiedSince = WebUtil::parseLastModified();
if($mapEtag === $reqMapEtag || $mapModified === $reqModifiedSince){
WebUtil::dieWithNotModified();
}
Json::die($mapInfo['data'], 0);
}
@@ -65,10 +60,9 @@ $rawMap = getWorldMap([
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$mapTheme = $gameStor->map_theme ?? 'che';
$rawMap['history'] = $history;
$rawMap['theme'] = $mapTheme;
$rawMap['theme'] = GameConst::$mapName;
$etag = hash('sha256', $serverID.$now);
$map = [
@@ -77,7 +71,6 @@ $map = [
'data'=>$rawMap,
];
$cache->save("recent_map", $map);
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $now)." GMT");
header("Etag: $etag");
WebUtil::setCacheHeader(new APICacheResult(TimeUtil::secondsToDateTime($now), $etag));
Json::die($map['data'], 0);
+1
View File
@@ -6,6 +6,7 @@ include "func.php";
WebUtil::requireAJAX();
/** @var int|null */
$pick = Util::getPost('pick', 'int');
if(!$pick){
+25 -20
View File
@@ -1,6 +1,9 @@
<?php
namespace sammo;
use Ds\Map;
use sammo\Enums\RankColumn;
include "lib.php";
include "func.php";
@@ -54,7 +57,7 @@ $defaultCheck = [
['year', 0]
],
'array'=>[
'attackerGeneral', 'attackerCity', 'attackerNation',
'attackerGeneral', 'attackerCity', 'attackerNation',
'defenderGenerals', 'defenderCity', 'defenderNation'
],
];
@@ -84,14 +87,14 @@ $rawDefenderNation = $query['defenderNation'];
$generalCheck = [
'required'=>[
'no', 'name', 'nation', 'turntime', 'personal', 'special2', 'crew', 'crewtype', 'atmos', 'train',
'intel', 'intel_exp', 'book', 'strength', 'strength_exp', 'weapon', 'injury', 'leadership', 'leadership_exp', 'horse', 'item',
'no', 'name', 'nation', 'turntime', 'personal', 'special2', 'crew', 'crewtype', 'atmos', 'train',
'intel', 'intel_exp', 'book', 'strength', 'strength_exp', 'weapon', 'injury', 'leadership', 'leadership_exp', 'horse', 'item',
'explevel', 'experience', 'dedication', 'officer_level', 'officer_city', 'gold', 'rice', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5',
'recent_war', 'warnum', 'killnum', 'killcrew',
],
'integer'=>[
'no', 'nation', 'crew', 'crewtype', 'atmos', 'train',
'intel', 'intel_exp', 'strength', 'strength_exp', 'injury', 'leadership', 'leadership_exp',
'intel', 'intel_exp', 'strength', 'strength_exp', 'injury', 'leadership', 'leadership_exp',
'explevel', 'experience', 'dedication', 'officer_level', 'officer_city', 'gold', 'rice', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5',
'warnum', 'killnum', 'killcrew',
],
@@ -154,18 +157,18 @@ foreach($rawDefenderList as $idx=>$rawDefenderGeneral){
]);
}
$rawDefenderGeneral['owner'] = 0;
$defenderList[] = new General($rawDefenderGeneral, extractRankVar($rawDefenderGeneral), $rawDefenderCity, $rawAttackerNation, $year, $month, true);
}
$cityCheck = [
'required'=>[
'city', 'nation', 'supply', 'name',
'pop', 'agri', 'comm', 'secu', 'def', 'wall',
'city', 'nation', 'supply', 'name',
'pop', 'agri', 'comm', 'secu', 'def', 'wall',
'trust', 'level',
'pop_max', 'agri_max', 'comm_max', 'secu_max', 'def_max', 'wall_max',
'dead', 'state', 'conflict',
'dead', 'state', 'conflict',
],
'numeric'=>[
'pop', 'agri', 'comm', 'secu', 'def', 'wall', 'trust', 'dead'
@@ -258,7 +261,7 @@ if($action == 'reorder'){
foreach($defenderList as $defenderGeneral){
$order[] = $defenderGeneral->getID();
}
Json::die([
'result'=>true,
'reason'=>'success',
@@ -280,19 +283,21 @@ $gameStor = KVStorage::getStorage($db, 'game_env');
$startYear = $gameStor->startyear;
$cityRate = Util::round(($year - $startYear) / 1.5) + 60;
function extractRankVar(array $rawVal):array{
$rankVars = [];
function extractRankVar(array $rawVal):Map{
$rankVars = new Map;
foreach($rawVal as $rawKey=>$rawVal){
if(key_exists($rawKey, General::RANK_COLUMN)){
$rankVars[$rawKey] = $rawVal;
$key = RankColumn::tryFrom($rawKey);
if($key === null){
continue;
}
$rankVars[$key] = $rawVal;
}
return $rankVars;
}
function simulateBattle(
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
$startYear, $year, $month, $cityRate
){
$attacker = new WarUnitGeneral(
@@ -310,7 +315,7 @@ function simulateBattle(
$attackerRice = $rawAttacker['rice'];
$defenderRice = 0;
$getNextDefender = function(?WarUnit $prevDefender, bool $reqNext)
$getNextDefender = function(?WarUnit $prevDefender, bool $reqNext)
use ($iterDefender, $rawDefenderCity, $rawDefenderNation, $year, $month, &$battleResult, &$defenderRice) {
if($prevDefender !== null){
$prevDefender->getLogger()->rollback();
@@ -393,13 +398,13 @@ $defendersActivatedSkills = [];
foreach(Util::range($repeatCnt) as $repeatIdx){
/** @var WarUnit $attacker */
[$attacker, $city, $battleResult, $conquerCity, $attackerRice, $defenderRice] = simulateBattle(
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
$startYear, $year, $month, $cityRate
);
$lastWarLog = Util::mapWithKey(function($key, $values){
return ConvertLog(join('<br>', $values));
}, $attacker->getLogger()->rollback());
}, $attacker->getLogger()->rollback());
$avgPhase += $attacker->getPhase() / $repeatCnt;
@@ -443,7 +448,7 @@ foreach(Util::range($repeatCnt) as $repeatIdx){
$activatedSkills[$skillName] += $skillCnt / $repeatCnt;
}
}
}
}
+1 -1
View File
@@ -18,7 +18,7 @@ $loader->addClassMap((function () {
//디버그용 매크로
ini_set("session.cache_expire", 10080); // minutes
ini_set("session.cache_expire", "10080"); // minutes
ob_start();
-1
View File
@@ -1 +0,0 @@
0
-53
View File
@@ -1,53 +0,0 @@
로그활성화
show variables like '%log%';
ALTER TABLE mysql.general_log
ADD COLUMN seq BIGINT UNSIGNED NOT NULL AUTO_INCREMENT AFTER argument,
ADD PRIMARY KEY(seq),
ENGINE=MYISAM;
set global expire_logs_days=7;
set global log_output='TABLE';
set global general_log=1;
select count(*) from mysql.general_log;
select * from mysql.general_log limit 100;
set global general_log=0;
truncate mysql.general_log;
캐시들
show variables like '%cache%';
show status like '%cache%';
show variables like '%key%';
show status like '%key%';
key_buffer_size 줄이자. 현16M -> 8M이하
myisam_sort_buffer_size 줄이자. 현8M -> 2M
innodb 설정
기존 Antelope 포맷은 가변컬럼의 767바이트까지만 저장하고 나머지는 offset하여 외부에 저장한다.
그런데 innodb는 1개 행이 최대 8KB만 저장 가능하므로 가변컬럼이 11개 이상인 경우는 오류 위험이 있다.
(MyISAM은 64KB)
Barracuda 포맷에 Dynamic 또는 Compressed를 사용하면 포인터 20바이트만 저장하고 실데이터는 외부에 저장한다.
[mysqld]
innodb_file_format=barracuda
innodb_file_per_table=1
innodb 최적화
innodb_buffer_pool_size: 체섭 테이블 최대 5M정도. 인덱스 포함해도 32M면 충분?
innodb_flush_method: 기본값대로. O_DIRECT는 메모리가 커서 캐시 2중 필요 없을때만.
innodb_file_per_table: 테이블마다 독립파일로 저장
innodb_flush_log_at_trx_commit: 기본1(커밋마다), 0(로그찰때만), 추천2(1초마다)
innodb_log_file_size: 현 5M, 많이 키워도 될듯
innodb_log_buffer_size: 기본 8M 적당
innodb_thread_concurrency: 코어개수 2배 정도
sync_binlog=0 이미 꺼져있음
ib_logfile0, ib_logfile1은 로그사이즈 바꾸면 재시작이 안되므로 지우고 다시 해야함
alter table table_name engine=innodb row_format=dynamic
+23 -10
View File
@@ -231,7 +231,10 @@ function processWar_NG(
$logger->pushGlobalActionLog("<D><b>{$attacker->getNationVar('name')}</b></>의 <Y>{$attacker->getName()}</>{$josaYi} <G><b>{$city->getName()}</b></>{$josaRo} 진격합니다.");
$logger->pushGeneralActionLog("<G><b>{$city->getName()}</b></>{$josaRo} <M>진격</>합니다. <1>$date</>");
for ($currPhase = 0; $currPhase < $attacker->getMaxPhase(); $currPhase += 1) {
$logWritten = false;
while($attacker->getPhase() < $attacker->getMaxPhase()){
$logWritten = false;
if ($defender === null) {
$defender = $city;
@@ -256,8 +259,8 @@ function processWar_NG(
}
}
if ($defender->getPhase() == 0) {
$defender->setPrePhase($currPhase);
if ($defender->getPhase() == 0 && $defender->getOppose() == null) {
$defender->setPrePhase($attacker->getPhase());
$attacker->addTrain(1);
$defender->addTrain(1);
@@ -266,10 +269,10 @@ function processWar_NG(
$defenderCrewTypeCoef = $defender->getCrewType()->getAttackCoef($attacker->getCrewType()) * $attacker->getCrewType()->getDefenceCoef($defender->getCrewType());
/*
if($attackerCrewTypeCoef > $defenderCrewTypeCoef && $attacker instanceof WarUnitGeneral){
$attacker->getGeneral()->increaseInheritancePoint('snipe_combat', 1);
$attacker->getGeneral()->increaseInheritancePoint(InheritanceKey::snipe_combat, 1);
}
if($defenderCrewTypeCoef > $attackerCrewTypeCoef && $defender instanceof WarUnitGeneral){
$defender->getGeneral()->increaseInheritancePoint('snipe_combat', 1);
$defender->getGeneral()->increaseInheritancePoint(InheritanceKey::snipe_combat, 1);
}
*/
@@ -347,15 +350,22 @@ function processWar_NG(
$attacker->increaseKilled($deadDefender);
$defender->increaseKilled($deadAttacker);
$phaseNickname = $currPhase + 1;
if($defender->getPhase() < 0){
$phaseNickname = '先';
}
else{
$currPhase = $attacker->getPhase() + 1;
$phaseNickname = "{$currPhase} ";
}
if ($deadAttacker > 0 || $deadDefender > 0) {
$attacker->getLogger()->pushGeneralBattleDetailLog(
"$phaseNickname : <Y1>【{$attacker->getName()}】</> <C>{$attacker->getHP()} (-$deadAttacker)</> VS <C>{$defender->getHP()} (-$deadDefender)</> <Y1>【{$defender->getName()}】</>"
"$phaseNickname: <Y1>【{$attacker->getName()}】</> <C>{$attacker->getHP()} (-$deadAttacker)</> VS <C>{$defender->getHP()} (-$deadDefender)</> <Y1>【{$defender->getName()}】</>"
);
$defender->getLogger()->pushGeneralBattleDetailLog(
"$phaseNickname : <Y1>【{$defender->getName()}】</> <C>{$defender->getHP()} (-$deadDefender)</> VS <C>{$attacker->getHP()} (-$deadAttacker)</> <Y1>【{$attacker->getName()}】</>"
"$phaseNickname: <Y1>【{$defender->getName()}】</> <C>{$defender->getHP()} (-$deadDefender)</> VS <C>{$attacker->getHP()} (-$deadAttacker)</> <Y1>【{$attacker->getName()}】</>"
);
}
@@ -364,6 +374,8 @@ function processWar_NG(
$defender->addPhase();
if (!$attacker->continueWar($noRice)) {
$logWritten = true;
$attacker->logBattleResult();
$defender->logBattleResult();
@@ -386,6 +398,7 @@ function processWar_NG(
}
if (!$defender->continueWar($noRice)) {
$logWritten = true;
$attacker->logBattleResult();
$defender->logBattleResult();
@@ -414,7 +427,7 @@ function processWar_NG(
$defender->getLogger()->pushGeneralActionLog("전멸했습니다.", ActionLogger::PLAIN);
}
if ($currPhase + 1 == $attacker->getMaxPhase()) {
if ($attacker->getPhase() >= $attacker->getMaxPhase()) {
break;
}
@@ -427,7 +440,7 @@ function processWar_NG(
}
}
if ($currPhase == $attacker->getMaxPhase()) {
if (!$logWritten) {
//마지막 페이즈의 전투 마무리
$attacker->logBattleResult();
$defender->logBattleResult();
-4
View File
@@ -1,4 +0,0 @@
<?php
require('../vendor/autoload.php');
//ParsedownExtra;
+4 -2
View File
@@ -16,8 +16,10 @@ include "func.php";
<title>최근 지도</title>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printStaticValues([
'serverNick' => DB::prefix(),
'serverID' => UniqueConst::$serverID
'staticValues' => [
'serverNick' => DB::prefix(),
'serverID' => UniqueConst::$serverID
],
]) ?>
<?= WebUtil::printJS('d_shared/base_map.js') ?>
@@ -6,13 +6,10 @@ use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\DTO\BettingInfo;
use sammo\General;
use sammo\KVStorage;
use sammo\Util;
use sammo\Validator;
use function sammo\increaseRefresh;
class GetBettingDetail extends \sammo\BaseAPI
{
public function validateArgs(): ?string
+12 -1
View File
@@ -7,6 +7,7 @@ use DateTimeInterface;
use sammo\DB;
use sammo\DTO\BettingInfo;
use sammo\KVStorage;
use sammo\Validator;
use function sammo\checkLimit;
use function sammo\increaseRefresh;
@@ -15,6 +16,11 @@ class GetBettingList extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('in', 'req', ['bettingNation', 'tournament']);
if (!$v->validate()) {
return $v->errorStr();
}
return null;
}
@@ -27,6 +33,8 @@ class GetBettingList extends \sammo\BaseAPI
{
$db = DB::db();
$reqType = $this->args['req'] ?? null;
increaseRefresh("베팅장", 1);
$gameStor = KVStorage::getStorage($db, 'game_env');
@@ -42,6 +50,9 @@ class GetBettingList extends \sammo\BaseAPI
$bettingList = [];
foreach ($bettingStor->getAll() as $_key => $rawItem) {
$item = new BettingInfo($rawItem);
if ($reqType !== null && $item->type != $reqType) {
continue;
}
unset($rawItem['candidates']);
$bettingList[$item->id] = $rawItem;
$bettingList[$item->id]['totalAmount'] = 0;
@@ -49,7 +60,7 @@ class GetBettingList extends \sammo\BaseAPI
[$year, $month] = $gameStor->getValuesAsArray(['year', 'month']);
if(!$bettingList){
if (!$bettingList) {
return [
'result' => true,
'bettingList' => $bettingList,
-1
View File
@@ -6,7 +6,6 @@ use sammo\Session;
use DateTimeInterface;
use sammo\Validator;
use function sammo\cutTurn;
use function sammo\pushGeneralCommand;
class PushCommand extends \sammo\BaseAPI
-1
View File
@@ -6,7 +6,6 @@ use sammo\Session;
use DateTimeInterface;
use sammo\Validator;
use function sammo\cutTurn;
use function sammo\repeatGeneralCommand;
class RepeatCommand extends \sammo\BaseAPI
@@ -0,0 +1,76 @@
<?php
namespace sammo\API\Command;
use sammo\Session;
use DateTimeInterface;
use sammo\GameConst;
use sammo\Util;
use sammo\Validator;
use function sammo\setGeneralCommand;
class ReserveBulkCommand extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
foreach ($this->args as $idx => $turn) {
$v = new Validator($turn);
$v->rule('required', [
'action',
'turnList'
])
->rule('lengthMin', 'action', 1)
->rule('integerArray', 'turnList');
if (!$v->validate()) {
return "{$idx}:{$v->errorStr()}";
}
}
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$briefList = [];
foreach ($this->args as $idx => $turn) {
$action = $turn['action'];
$turnList = $turn['turnList'];
$arg = $turn['arg'] ?? [];
if (!$turnList) {
return "{$idx}: 턴이 입력되지 않았습니다";
}
if (!in_array($action, Util::array_flatten(GameConst::$availableGeneralCommand))) {
return "{$idx}: 사용할 수 없는 커맨드입니다.";
}
if (!is_array($arg)) {
return "{$idx}: 올바른 arg 형태가 아닙니다.";
}
$partialResult = setGeneralCommand($session->generalID, $turnList, $action, $arg);
if(!$partialResult['result']){
return [
'result' => false,
'briefList' => $briefList,
'errorIdx' => $idx,
'reason' => $partialResult['reason']
];
}
$briefList[$idx] = $partialResult['brief'];
}
return [
'result' => true,
'briefList' => $briefList,
'reason' => 'success'
];
}
}
+68
View File
@@ -0,0 +1,68 @@
<?php
namespace sammo\API\General;
use sammo\DB;
use sammo\Validator;
use sammo\Session;
use sammo\GameConst;
use sammo\General;
use sammo\JosaUtil;
class DropItem extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('required', [
'itemType',
])
->rule('in', 'itemType', array_keys(GameConst::$allItems));
if (!$v->validate()) {
return "{$v->errorStr()}";
}
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$generalID = $session->generalID;
$me = General::createGeneralObjFromDB($generalID);
$itemType = $this->args['itemType'];
$item = $me->getItem($itemType);
if ($item->getRawClassName() === 'None') {
return '아이템을 가지고 있지 않습니다.';
}
$me->setItem($itemType, 'None');
$logger = $me->getLogger();
$generalName = $me->getName();
$josaYi = JosaUtil::pick($generalName, '이');
$itemName = $item->getName();
$itemRawName = $item->getRawName();
$josaUl = JosaUtil::pick($itemRawName, '을');
$logger->pushGeneralActionLog("<C>{$itemName}</>{$josaUl} 버렸습니다.");
$nationName = $me->getStaticNation()['name'];
if (!$item->isBuyable()) {
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 잃었습니다!");
$logger->pushGlobalHistoryLog("<R><b>【망실】</b></><D><b>{$nationName}</b></>의 <Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 잃었습니다!");
}
$me->applyDB(DB::db());
return null;
}
}
+51
View File
@@ -0,0 +1,51 @@
<?php
namespace sammo\API\General;
use sammo\Validator;
use sammo\API\Nation\GetGeneralLog as GetNationGeneralLog;
use sammo\Session;
class GetGeneralLog extends GetNationGeneralLog
{
const GENERAL_HISTORY = 'generalHistory';
const GENERAL_ACTION = 'generalAction';
const BATTLE_RESULT = 'battleResult';
const BATTLE_DETAIL = 'battleDetail';
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v
->rule('required', [
'type',
])
->rule('integer', [
'reqTo',
])
->rule('in', 'type', [
self::GENERAL_HISTORY,
self::GENERAL_ACTION,
self::BATTLE_RESULT,
self::BATTLE_DETAIL,
]);
if (!$v->validate()) {
return $v->errorStr();
}
if (key_exists('reqTo', $this->args)) {
$this->args['reqTo'] = (int)$this->args['reqTo'];
}
return null;
}
public function checkPermission(array $me): ?string
{
return null;
}
public function getTargetGeneralID(Session $session): int{
return $session->generalID;
}
}
+9 -7
View File
@@ -5,9 +5,11 @@ namespace sammo\API\General;
use sammo\ActionLogger;
use sammo\CityConst;
use sammo\DB;
use sammo\Enums\RankColumn;
use sammo\GameConst;
use sammo\GameUnitConst;
use sammo\General;
use sammo\InheritancePointManager;
use sammo\JosaUtil;
use sammo\Json;
use sammo\KVStorage;
@@ -26,7 +28,6 @@ use function sammo\cutTurn;
use function sammo\getGeneralSpecialWarName;
use function sammo\getRandTurn;
use function sammo\pushAdminLog;
use function sammo\applyInheritanceUser;
class Join extends \sammo\BaseAPI
{
@@ -155,7 +156,8 @@ class Join extends \sammo\BaseAPI
$admin = $gameStor->getValues(['scenario', 'turnterm', 'turntime', 'show_img_level', 'startyear', 'year', 'month']);
$inheritTotalPoint = applyInheritanceUser($userID);
$inheritPointManager = InheritancePointManager::getInstance();
$inheritTotalPoint = $inheritPointManager->applyInheritanceUser($userID);
$inheritRequiredPoint = 0;
$userLogger = new UserLogger($userID, $admin['year'], $admin['month'], false);
@@ -368,18 +370,15 @@ class Join extends \sammo\BaseAPI
$db->insert('general_turn', $turnRows);
$rank_data = [];
foreach (array_keys(General::RANK_COLUMN) as $rankColumn) {
foreach (RankColumn::cases() as $rankColumn) {
$rank_data[] = [
'general_id' => $generalID,
'nation_id' => 0,
'type' => $rankColumn,
'type' => $rankColumn->value,
'value' => 0
];
}
$db->insert('rank_data', $rank_data);
$db->insert('betting', [
'general_id' => $generalID,
]);
$cityname = CityConst::byID($city)->name;
@@ -388,6 +387,9 @@ class Join extends \sammo\BaseAPI
$inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$userID}");
$inheritStor->setValue('previous', [$inheritTotalPoint - $inheritRequiredPoint, null]);
$userLogger->flush();
$db->update('rank_data', [
'value'=>$db->sqleval('value + %i', $inheritRequiredPoint)
], 'general_id = %i AND type = %s', $generalID, RankColumn::inherit_point_spent_dynamic->value);
}
$me = [
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace sammo\API\Global;
use sammo\Session;
use DateTimeInterface;
use sammo\TurnExecutionHelper;
class ExecuteEngine extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
return null;
}
public function getRequiredSessionMode(): int
{
return static::NO_SESSION;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$updated = TurnExecutionHelper::executeAllCommand();
return [
'result' => true,
'updated' => $updated,
];
}
}
+154
View File
@@ -0,0 +1,154 @@
<?php
namespace sammo\API\Global;
use sammo\DB;
use sammo\Json;
use sammo\KVStorage;
use sammo\RootDB;
use sammo\Session;
use function sammo\calcLeadershipBonus;
use function sammo\checkLimit;
use function sammo\getDed;
use function sammo\getExpLevel;
use function sammo\getGenChar;
use function sammo\getGeneralSpecialDomesticName;
use function sammo\getGeneralSpecialWarName;
use function sammo\getHonor;
use function sammo\getNationStaticInfo;
use function sammo\getOfficerLevelText;
use function sammo\increaseRefresh;
class GeneralList extends \sammo\BaseAPI
{
static $withToken = false;
public function validateArgs(): ?string
{
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_LOGIN;
}
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$userID = $session->userID;
if ($session->isGameLoggedIn()) {
increaseRefresh("장수일람", 2);
$me = $db->queryFirstRow('SELECT con, turntime FROM general WHERE owner=%i', $userID);
$con = checkLimit($me['con']);
if ($con >= 2) {
return '접속 제한중입니다. 1턴 이내에 너무 많은 갱신을 하셨습니다.';
}
} else {
$availableNextCall = $session->availableNextCallGetGeneralList ?? '2000-01-01 00:00:00';
$now = new \DateTimeImmutable();
if ($now <= new \DateTimeImmutable($availableNextCall) && $session->userGrade < 5) {
return "장수 리스트는 10초에 한번 갱신 가능합니다.\n다음 시간 : " . $availableNextCall;
}
$availableNextCall = $now->add(new \DateInterval('PT10S'))->format('Y-m-d H:i:s');
$session->availableNextCallGetGeneralList = $availableNextCall;
}
$session->setReadOnly();
$rawGeneralList = $db->queryAllLists('SELECT owner,no,picture,imgsvr,npc,age,nation,special,special2,personal,name,owner_name as ownerName,injury,leadership,strength,intel,experience,dedication,officer_level,killturn,connect from general');
$ownerNameList = [];
if ($gameStor->isunited) {
foreach (RootDB::db()->queryAllLists('SELECT no, name FROM member') as [$ownerID, $ownerName]) {
$ownerNameList[$ownerID] = $ownerName;
}
}
$generalList = [];
foreach ($rawGeneralList as $rawGeneral) {
[$owner, $no, $picture, $imgsvr, $npc, $age, $nation, $special, $special2, $personal, $name, $ownerName, $injury, $leadership, $strength, $intel, $experience, $dedication, $officerLevel, $killturn, $connectCnt] = $rawGeneral;
if (key_exists($owner, $ownerNameList)) {
$ownerName = $ownerNameList[$owner];
}
$nationArr = getNationStaticInfo($nation);
$lbonus = calcLeadershipBonus($officerLevel, $nationArr['level']);
$generalList[] = [
$no,
$picture,
$imgsvr,
$npc,
$age,
$nationArr['name'],
getGeneralSpecialDomesticName($special),
getGeneralSpecialWarName($special2),
getGenChar($personal),
$name,
$npc == 1 ? $ownerName : null,
$injury,
$leadership,
$lbonus,
$strength,
$intel,
getExpLevel($experience),
getHonor($experience),
getDed($dedication),
getOfficerLevelText($officerLevel, $nationArr['level']),
$killturn,
$connectCnt
];
}
$resultColumns = [
'no',
'picture',
'imgsvr',
'npc',
'age',
'nationName',
'special',
'special2',
'personal',
'name',
'ownerName',
'injury',
'leadership',
'lbonus',
'strength',
'intel',
'explevel',
'honorText',
'dedLevelText',
'officerLevelText',
];
$result = [
'result' => 'true',
'column' => $resultColumns,
'list' => $generalList,
];
if (static::$withToken) {
$now = (new \DateTimeImmutable())->format('Y-m-d H:i:s');
$tokens = [];
foreach ($db->query('SELECT * FROM select_npc_token WHERE `valid_until`>=%s', $now) as $token) {
$validUntil = $token['valid_until'];
foreach (Json::decode($token['pick_result']) as $pickResult) {
$tokens[$pickResult['no']] = $pickResult['keepCnt'];
}
}
$result['token'] = $tokens;
}
return $result;
}
}
@@ -0,0 +1,8 @@
<?php
namespace sammo\API\Global;
class GeneralListWithToken extends GeneralList
{
static $withToken = true;
}
+101
View File
@@ -0,0 +1,101 @@
<?php
namespace sammo\API\Global;
use sammo\Session;
use DateTimeInterface;
use Nette\Caching\Cache;
use sammo\APICacheResult;
use sammo\GameConst;
use sammo\MapRequest;
use sammo\TimeUtil;
use sammo\UniqueConst;
use sammo\Util;
use sammo\Validator;
use function sammo\getGlobalHistoryLogRecent;
use function sammo\getWorldMap;
use function sammo\prepareDir;
class GetCachedMap extends \sammo\BaseAPI
{
const CACHE_SECONDS = 600;
private ?\DateTimeInterface $cachedTime = null;
public function validateArgs(): ?string
{
return null;
}
public function tryCache(): ?APICacheResult
{
if ($this->cachedTime === null) {
return null;
}
$now = TimeUtil::nowDateTimeImmutable();
$diff = TimeUtil::DateIntervalToSeconds($this->cachedTime->diff($now));
$nextCacheTime = self::CACHE_SECONDS - $diff;
return new APICacheResult($this->cachedTime, null, Util::toInt($nextCacheTime), true);
}
public function getRequiredSessionMode(): int
{
return static::NO_SESSION;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
if (!class_exists('\\sammo\\UniqueConst')) {
return '서버 초기화되지 않음';
}
if (!prepareDir('data/file_cache')) {
return 'cache 불가';
}
$storage = new \Nette\Caching\Storages\FileStorage('data/file_cache');
$cache = new Cache($storage);
$now = TimeUtil::nowDateTimeImmutable();
if ($modifiedSince) {
$diff = TimeUtil::DateIntervalToSeconds($modifiedSince->diff($now));
if (0 <= $diff && $diff < self::CACHE_SECONDS) {
$this->cachedTime = $modifiedSince;
return null;
}
}
$mapInfo = $cache->load("recent_map");
if ($mapInfo) {
$cachedTime = TimeUtil::secondsToDateTime($mapInfo['timestamp'], true, true);
$diff = $cachedTime->diff($now);
if (0 <= $diff && $diff < self::CACHE_SECONDS) {
$this->cachedTime = $cachedTime;
return $mapInfo['data'];
}
}
$history = getGlobalHistoryLogRecent(10);
$cachedMap = getWorldMap([
'year' => null,
'month' => null,
'aux' => null,
'neutralView' => true,
'showMe' => false,
]);
$cachedMap['history'] = $history;
$cachedMap['theme'] = GameConst::$mapName;
$timestamp = $now->getTimestamp();
$this->cachedTime = $now;
$map = [
'timestamp' => $timestamp,
'data' => $cachedMap,
];
$cache->save("recent_map", $map);
return $cachedMap;
}
}
+321
View File
@@ -0,0 +1,321 @@
<?php
namespace sammo\API\Global;
use sammo\Session;
use DateTimeInterface;
use sammo\VersionGit;
use Nette\Caching\Cache;
use RuntimeException;
use sammo\APICacheResult;
use sammo\CityConst;
use sammo\GameConst;
use sammo\GameUnitConst;
use sammo\Json;
use sammo\TimeUtil;
use sammo\UniqueConst;
use function sammo\prepareDir;
class GetConst extends \sammo\BaseAPI
{
/** 반환하는 StaticValues 타입이 달라지면 +1 */
const CONST_API_VERSION = 2;
const CACHE_KEY = 'JSConst';
private ?string $cacheKey = null;
public function validateArgs(): ?string
{
return null;
}
public function getRequiredSessionMode(): int
{
return static::NO_SESSION;
}
public function findLastModified(): ?int
{
$rawResult = explode("\n", shell_exec('git status -u -s --no-rename'));
$files = [];
foreach ($rawResult as $rawLine) {
if (strlen($rawLine) < 3) {
continue;
}
$filePath = trim(substr($rawLine, 3));
if ($filePath[0] == '"') {
$filePath = substr($filePath, 1, strlen($filePath) - 2);
}
if (!file_exists($filePath)) {
continue;
}
$files[] = $filePath;
}
$lastModified = null;
foreach ($files as $filePath) {
$fileModified = filemtime($filePath);
if ($fileModified === false) {
continue;
}
if ($lastModified === null) {
$lastModified = $fileModified;
continue;
}
if ($lastModified > $fileModified) {
continue;
}
$lastModified = $fileModified;
}
if ($lastModified === null) {
return null;
}
return $lastModified;
}
public function getCacheKey(): string
{
if ($this->cacheKey !== null) {
return $this->cacheKey;
}
if (is_subclass_of('\\sammo\\VersionGit', '\\sammo\VersionGitDynamic')) {
$lastModified = $this->findLastModified();
if ($lastModified !== null) {
$versionHash = "lt{$lastModified}";
} else {
$versionHash = VersionGit::getHash();
}
} else {
$versionHash = VersionGit::getHash();
}
$apiVersion = static::CONST_API_VERSION;
$serverID = UniqueConst::$serverID;
$cacheKey = "{$apiVersion}_{$serverID}_{$versionHash}";
$this->cacheKey = $cacheKey;
return $cacheKey;
}
public function tryCache(): ?APICacheResult
{
if (is_subclass_of('\\sammo\\VersionGit', '\\sammo\VersionGitDynamic')) {
return new APICacheResult(TimeUtil::secondsToDateTime($this->findLastModified()??\time(), true, true));
}
return new APICacheResult(null, $this->getCacheKey(), 60, true);
}
public function readCache(Cache $cache): null|string|array|int|float|bool
{
$rawJSONCache = $cache->load(static::CACHE_KEY);
if ($rawJSONCache === null) {
return null;
}
$jsonCache = Json::decode($rawJSONCache);
if (!key_exists('cacheKey', $jsonCache)) {
return null;
}
$jsonCacheKey = $jsonCache['cacheKey'];
if ($jsonCacheKey !== $this->getCacheKey()) {
return null;
}
return $jsonCache['data'] ?? null;
}
public function extractObjClassInfo(string $objKey, callable $callerFunction): array
{
/** @var \sammo\iAction */
$target = $callerFunction($objKey);
if (!($target instanceof \sammo\iAction)) {
throw new \RuntimeException("{$objKey}의 대상이 iAction이 아님");
}
return [
'value' => $objKey,
'name' => $target->getName(),
'info' => $target->getInfo(),
];
}
public function extractObjClassInfoFromArray(array $constArray, callable $callerFunction): array
{
$result = [];
foreach ($constArray as $key => $target) {
if (is_string($target)) {
$actionInfo = $this->extractObjClassInfo($target, $callerFunction);
if (is_string($key)) {
$result[$key] = $actionInfo;
} else {
$result[$target] = $actionInfo;
}
continue;
}
if (is_array($target)) {
$result[$key] = $this->extractObjClassInfoFromArray($target, $callerFunction);
continue;
}
if(is_string($key) && is_int($target)){
//역전된 상황이다.
$result[$key] = $this->extractObjClassInfo($key, $callerFunction);
continue;
}
$result[$key] = $target;
}
return $result;
}
public function extractObjClassInfoFromGameConst(string $gameConstKey, callable $callerFunction): array
{
$gameConstKeyList = explode(".", $gameConstKey);
$target = (GameConst::${$gameConstKeyList[0]}) ?? [];
foreach(\array_slice($gameConstKeyList, 1) as $gameConstSubKey){
$target = $target[$gameConstSubKey] ?? [];
}
if (is_string($target)) {
return [$target => $this->extractObjClassInfo($target, $callerFunction)];
}
if (!is_array($target)) {
throw new \RuntimeException("GameConst::{$gameConstKey}의 값이 {$target}");
}
return $this->extractObjClassInfoFromArray($target, $callerFunction);
}
public function genConstData()
{
/** @var array<string,array{0:string,1:string[],2?:int> */
$gameConstKeys = [
'nationType' => [
'\sammo\buildNationTypeClass',
['availableNationType', 'neutralNationType']
],
'specialDomestic' => [
'\sammo\buildGeneralSpecialDomesticClass',
['defaultSpecialDomestic', 'availableSpecialDomestic', 'optionalSpecialDomestic']
],
'specialWar' => [
'\sammo\buildGeneralSpecialWarClass',
['defaultSpecialWar', 'availableSpecialWar', 'optionalSpecialWar']
],
'personality' => [
'\sammo\buildPersonalityClass',
['neutralPersonality', 'availablePersonality', 'optionalPersonality']
],
'item' => [
'\sammo\buildItemClass',
['allItems'],
1
],
];
//GameConst 중 BaseCommand는 시간 흐름, 장수에 따라 정보가 달라지므로 따로 처리해야함
$iActionInfo = [];
$iActionKeyMap = [];
foreach ($gameConstKeys as $mappedKey => $callerTarget) {
$flatLevel = 0;
if (is_array($callerTarget)) {
$callerFunction = $callerTarget[0];
$gameConstSubKey = $callerTarget[1];
if(count($callerTarget) > 2){
/** @var int */
$flatLevel = $callerTarget[2];
}
} else {
$gameConstSubKey = [$mappedKey];
$callerFunction = $callerTarget;
}
if (!is_callable($callerFunction)) {
throw new \RuntimeException("{$mappedKey} => {$callerFunction}이 callable이 아님");
}
$actionInfo = [];
foreach ($gameConstSubKey as $key) {
$appendInfo = $this->extractObjClassInfoFromGameConst($key, $callerFunction);
$actionInfo = array_merge($actionInfo, $appendInfo);
$iActionKeyMap[$key] = $mappedKey;
}
if($flatLevel > 0){
foreach(range(0, $flatLevel - 1) as $tryFlatLevel){
$actionInfo = array_merge(...array_values($actionInfo));
}
}
$iActionInfo[$mappedKey] = $actionInfo;
}
$crewtypeMap = [];
foreach(GameUnitConst::all() as $crewtypeObj){
$crewtypeMap[$crewtypeObj->id] = [
'value'=>(string)$crewtypeObj->id,
'name'=>$crewtypeObj->name,
'info'=>$crewtypeObj->getInfo(),
];
}
$iActionInfo['crewtype'] = $crewtypeMap;
return [
'gameConst' => get_class_vars('\sammo\GameConst'),
'gameUnitConst' => GameUnitConst::all(),
'cityConst' => CityConst::all(),
'cityConstMap' => [
'region' => CityConst::$regionMap,
'level' => CityConst::$levelMap,
],
'iActionInfo' => $iActionInfo,
'iActionKeyMap' => $iActionKeyMap,
];
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$cacheDir = $this->rootPath . '/data/file_cache';
if (!prepareDir($cacheDir)) {
throw new RuntimeException('cache 폴더 없음');
}
$storage = new \Nette\Caching\Storages\FileStorage($cacheDir);
$cache = new Cache($storage);
$currentCacheKey = $this->tryCache();
if($modifiedSince !== null && $currentCacheKey->lastModified == $modifiedSince){
return null;
}
if($reqEtag !== null && $currentCacheKey->etag == $reqEtag){
return null;
}
$constCache = $this->readCache($cache);
if ($constCache !== null) {
return [
'result' => true,
'cacheKey' => $this->getCacheKey(),
'data' => $constCache,
];
}
$constCache = $this->genConstData();
$cache->save(static::CACHE_KEY, Json::encode([
'cacheKey' => $this->getCacheKey(),
'data' => $constCache
]));
return [
'result' => true,
'cacheKey' => $this->getCacheKey(),
'data' => $constCache,
];
}
}
@@ -0,0 +1,31 @@
<?php
namespace sammo\API\Global;
use sammo\Session;
use DateTimeInterface;
use function sammo\getCurrentHistory;
class GetCurrentHistory 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)
{
$history = getCurrentHistory();
return [
'result' => true,
'data' => $history,
];
}
}
+105
View File
@@ -0,0 +1,105 @@
<?php
namespace sammo\API\Global;
use sammo\DB;
use sammo\Json;
use sammo\KVStorage;
use sammo\Session;
use function sammo\getAllNationStaticInfo;
use function sammo\increaseRefresh;
class GetDiplomacy 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)
{
$userID = $session->userID;
increaseRefresh("중원정보", 1);
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$myNationID = $db->queryFirstField('SELECT nation FROM general WHERE owner=%i', $userID);
$nations = array_filter(getAllNationStaticInfo(), function (array $nation) {
return $nation['level'];
});
uasort($nations, function (array $lhs, array $rhs) {
return - ($lhs['power'] <=> $rhs['power']);
});
foreach(array_keys($nations) as $nationID){
$nations[$nationID]['cities'] = [];
}
$realConflict = [];
foreach ($db->queryAllLists('SELECT nation, city, name, conflict FROM city') as [
$nationID,
$cityID,
$cityName,
$rawConflict
]) {
if($nationID != 0){
$nations[$nationID]['cities'][] = $cityName;
}
if($rawConflict == '{}'){
continue;
}
$rawConflict = Json::decode($rawConflict);
if (count($rawConflict) < 2) {
continue;
}
$sum = array_sum($rawConflict);
$conflict = [];
foreach ($rawConflict as $nationID => $killnum) {
$conflict[$nationID] = round(100 * $killnum / $sum, 1);
}
$realConflict[] = [$cityID, $conflict];
};
$neutralDiplomacyMap = [
3 => 2,
4 => 2,
5 => 2,
6 => 2,
7 => 2,
];
$diplomacyList = [];
foreach ($db->queryAllLists('SELECT me, you, state FROM diplomacy') as [$me, $you, $state]) {
if (!key_exists($me, $diplomacyList)) {
$diplomacyList[$me] = [];
}
if ($me != $myNationID && $you != $myNationID) {
$diplomacyList[$me][$you] = $neutralDiplomacyMap[$state] ?? $state;
} else {
$diplomacyList[$me][$you] = $state;
}
}
return [
'result' => true,
'nations' => array_values($nations),
'conflict' => $realConflict,
'diplomacyList' => $diplomacyList,
'myNationID' => $myNationID,
];
}
}
+188
View File
@@ -0,0 +1,188 @@
<?php
namespace sammo\API\Global;
use sammo\Session;
use DateTimeInterface;
use sammo\APICacheResult;
use sammo\DB;
use sammo\Json;
use sammo\UniqueConst;
use sammo\Util;
use sammo\Validator;
use function sammo\checkLimit;
use function sammo\increaseRefresh;
use function sammo\templateLimitMsg;
class GetHistory extends \sammo\BaseAPI
{
public string|null $cacheHash = null;
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('required', ['year', 'month'])
->rule('lengthMin', 'serverID', 1)
->rule('integer', 'year')
->rule('integer', 'month');
if (!$v->validate()) {
return $v->errorStr();
}
if (!$this->args['serverID']) {
$this->args['serverID'] = UniqueConst::$serverID;
}
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_LOGIN | static::REQ_READ_ONLY;
}
public function tryCache(): ?APICacheResult
{
if (!$this->cacheHash) {
return null;
}
return new APICacheResult(
null,
$this->getCacheKey($this->args['serverID'], $this->args['year'], $this->args['month'], $this->cacheHash)
);
}
private function getHistory(string $serverID, int $year, int $month): array
{
$db = DB::db();
$history = $db->queryFirstRow(
'SELECT * FROM ng_history WHERE server_id = %s AND year = %i AND month = %i',
$serverID,
$year,
$month
);
$hash = hash(
'sha256',
"[" . join(',', [
$history['global_history'],
$history['global_action'],
$history['nations'],
$history['map'],
]) . "]"
);
$history['global_history'] = Json::decode($history['global_history']);
$history['global_action'] = Json::decode($history['global_action']);
$history['nations'] = Json::decode($history['nations']);
$history['map'] = Json::decode($history['map']);
$history['hash'] = $hash;
return $history;
}
public function parseEtag(?string $etag): ?array
{
if (!$etag) {
return null;
}
$tags = explode('-', $etag);
if (count($tags) != 4) {
return null;
}
if (!is_numeric($tags[1])) {
return null;
}
if (!is_numeric($tags[2])) {
return null;
}
return [$tags[0], Util::toInt($tags[1]), Util::toInt($tags[2]), $tags[3]];
}
public function getCacheKey(string $serverID, int $year, int $month, string $cacheHash): string
{
return "{$serverID}-{$year}-{$month}-{$cacheHash}";
}
public function checkCached(?string $reqEtag): ?string
{
if (!$reqEtag) {
return null;
}
$parsedTags = $this->parseEtag($reqEtag);
if (!$parsedTags) {
return null;
}
$serverID = $this->args['serverID'];
$year = Util::toInt($this->args['year']);
$month = Util::toInt($this->args['month']);
[$cachedServerID, $cachedYear, $cachedMonth, $cachedHash] = $parsedTags;
if ($cachedServerID !== $serverID || $cachedYear !== $year || $cachedMonth !== $month) {
return null;
}
//tag로 hash를 굳이 붙이고 왔다면, 이미 데이터를 가지고 있다고 가정한다.
return $cachedHash;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$checkCache = $this->checkCached($reqEtag);
if ($checkCache) {
$this->cacheHash = $checkCache;
return null;
}
$serverID = $this->args['serverID'];
$year = $this->args['year'];
$month = $this->args['month'];
$db = DB::db();
if ($serverID === UniqueConst::$serverID) {
if (!$session->isGameLoggedIn()) {
return '진행중인 서버의 연감은 게임에 로그인해야 볼 수 있습니다.';
}
increaseRefresh("연감", 1);
$me = $db->queryFirstRow('SELECT con, turntime FROM general WHERE owner = %i', $session->userID);
if (!$me) {
return '장수가 사망했습니다.';
}
$con = checkLimit($me['con']);
if ($con >= 2) {
return templateLimitMsg($me['turntime']);
}
}
[$f_year, $f_month] = $db->queryFirstList(
'SELECT year, month FROM ng_history WHERE server_id = %s ORDER BY year ASC, month ASC LIMIT 1',
$serverID
);
if ($f_year === null || $f_month === null) {
return '올바르지 않은 서버 아이디입니다.';
}
$firstYearMonth = Util::joinYearMonth($f_year, $f_month);
[$l_year, $l_month] = $db->queryFirstList(
'SELECT year, month FROM ng_history WHERE server_id = %s ORDER BY year DESC, month DESC LIMIT 1',
$serverID
);
$lastYearMonth = Util::joinYearMonth($l_year, $l_month);
$queryYearMonth = Util::joinYearMonth($year, $month);
if ($queryYearMonth < $firstYearMonth || $queryYearMonth > $lastYearMonth) {
return '올바르지 않은 범위입니다.';
}
$history = $this->getHistory($serverID, $year, $month);
$this->cacheHash = $history['hash'];
return [
'result' => true,
'data' => $history,
];
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
namespace sammo\API\Global;
use sammo\Session;
use DateTimeInterface;
use sammo\MapRequest;
use sammo\Validator;
use function sammo\getWorldMap;
class GetMap extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('in', 'neutralView', [0, 1])
->rule('in', 'showMe', [0, 1]);
if (!$v->validate()) {
return $v->errorStr();
}
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
return getWorldMap(new MapRequest([
'neutralView' => !!($this->args['neutralView'] ?? false),
'showMe' => !!($this->args['showMe'] ?? false),
]));
}
}
@@ -5,6 +5,7 @@ namespace sammo\API\InheritAction;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\Enums\RankColumn;
use sammo\GameConst;
use sammo\General;
use sammo\KVStorage;
@@ -80,6 +81,7 @@ class BuyHiddenBuff extends \sammo\BaseAPI
$inheritBuffList[$type] = $level;
$general->setAuxVar('inheritBuff', $inheritBuffList);
$inheritStor->setValue('previous', [$previousPoint - $reqAmount, null]);
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $reqAmount);
$general->applyDB($db);
return null;
}
@@ -5,6 +5,7 @@ namespace sammo\API\InheritAction;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\Enums\RankColumn;
use sammo\GameConst;
use sammo\General;
use sammo\KVStorage;
@@ -52,6 +53,7 @@ class BuyRandomUnique extends \sammo\BaseAPI
$general->setAuxVar('inheritRandomUnique', TimeUtil::now());
$inheritStor->setValue('previous', [$previousPoint - $reqAmount, null]);
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $reqAmount);
$general->applyDB($db);
return null;
}
@@ -5,6 +5,7 @@ namespace sammo\API\InheritAction;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\Enums\RankColumn;
use sammo\GameConst;
use sammo\General;
use sammo\KVStorage;
@@ -66,6 +67,19 @@ class BuySpecificUnique extends \sammo\BaseAPI
return '이미 입찰한 아이템입니다. 다음 턴에 시도해 주세요.';
}
foreach(GameConst::$allItems as $itemType => $items){
if(!key_exists($itemKey, $items)){
continue;
}
$prevItem = $general->getItem($itemType);
if(!$prevItem->isBuyable()){
return '이미 같은 자리에 유니크를 보유하고 있습니다.';
}
break;
}
$db = DB::db();
$inheritStor = KVStorage::getStorage($db, "inheritance_{$userID}");
$trialStor = KVStorage::getStorage($db, "ut_{$itemKey}");
@@ -82,6 +96,7 @@ class BuySpecificUnique extends \sammo\BaseAPI
$itemTrials[$itemKey] = $amount;
$general->setAuxVar('inheritUniqueTrial', $itemTrials);
$inheritStor->setValue('previous', [$previousPoint - $amount, null]);
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $amount);
$trialStor->setValue("u{$userID}", [$userID, $generalID, $amount]);
$general->applyDB($db);
return null;
@@ -5,6 +5,7 @@ namespace sammo\API\InheritAction;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\Enums\RankColumn;
use sammo\GameConst;
use sammo\General;
use sammo\KVStorage;
@@ -68,6 +69,7 @@ class ResetSpecialWar extends \sammo\BaseAPI
$general->setAuxVar('inheritResetSpecialWar', $nextLevel);
$general->setVar('special2', 'None');
$inheritStor->setValue('previous', [$previousPoint - $reqPoint, null]);
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $reqPoint);
$general->applyDB($db);
return null;
}
@@ -6,6 +6,7 @@ use DateTimeImmutable;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\Enums\RankColumn;
use sammo\GameConst;
use sammo\General;
use sammo\KVStorage;
@@ -52,7 +53,7 @@ class ResetTurnTime extends \sammo\BaseAPI
return '충분한 유산 포인트를 가지고 있지 않습니다.';
}
$gameStor = new KVStorage($db, 'game_env');
$gameStor = KVStorage::getStorage($db, 'game_env');
[$turnTerm, $serverTurnTime] = $gameStor->getValuesAsArray(['turnterm', 'turntime']);
$currTurnTime = new DateTimeImmutable($general->getTurnTime());
@@ -77,6 +78,7 @@ class ResetTurnTime extends \sammo\BaseAPI
$general->setVar('turntime', TimeUtil::format($turnTime, true));
$general->setAuxVar('inheritResetTurnTime', $nextLevel);
$inheritStor->setValue('previous', [$previousPoint - $reqPoint, null]);
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $reqPoint);
$general->applyDB($db);
return null;
}
@@ -5,6 +5,7 @@ namespace sammo\API\InheritAction;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\Enums\RankColumn;
use sammo\GameConst;
use sammo\General;
use sammo\KVStorage;
@@ -77,6 +78,7 @@ class SetNextSpecialWar extends \sammo\BaseAPI
$general->setAuxVar('inheritSpecificSpecialWar', $type);
$inheritStor->setValue('previous', [$previousPoint - $reqAmount, null]);
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $reqAmount);
$general->applyDB($db);
return null;
}
+292
View File
@@ -0,0 +1,292 @@
<?php
namespace sammo\API\Nation;
use sammo\DB;
use sammo\General;
use sammo\Session;
use sammo\Util;
use function sammo\calcLeadershipBonus;
use function sammo\checkLimit;
use function sammo\checkSecretPermission;
use function sammo\getBillByLevel;
use function sammo\getDedLevelText;
use function sammo\getHonor;
use function sammo\getNationStaticInfo;
use function sammo\getOfficerLevelText;
use function sammo\increaseRefresh;
class GeneralList extends \sammo\BaseAPI
{
private int $permission;
static $viewColumns = [
'no' => 0,
'name' => 0,
'nation' => 0,
'npc' => 0,
'injury' => 0,
'leadership' => 0,
'strength' => 0,
'intel' => 0,
'explevel' => 0,
'dedlevel' => 0,
'gold' => 0,
'rice' => 0,
'killturn' => 0,
'picture' => 0,
'imgsvr' => 0,
'age' => 0,
'special' => 0,
'special2' => 0,
'personal' => 0,
'belong' => 0,
'connect' => 0,
'con' => 1,
'specage' => 1,
'specage2' => 1,
'leadership_exp' => 1,
'strength_exp' => 1,
'intel_exp' => 1,
'dex1' => 1,
'dex2' => 1,
'dex3' => 1,
'dex4' => 1,
'dex5' => 1,
'city' => 1,
'experience' => 1,
'dedication' => 1,
'officer_level' => 1,
'officer_city' => 1,
'defence_train' => 1,
'troop' => 1,
'crewtype' => 1,
'crew' => 1,
'train' => 1,
'atmos' => 1,
'turntime' => 1,
'horse' => 1,
'weapon' => 1,
'book' => 1,
'item' => 1,
'recent_war' => 1,
'aux' => 1,
'owner_name' => 9, //안씀.
//RANK
'warnum' => 1,
'killnum' => 1,
'deathnum' => 1,
'killcrew' => 1,
'deathcrew' => 1,
'firenum' => 1,
];
static $columnRemap = [
'special' => 'specialDomestic',
'special2' => 'specialWar',
'aux' => null,
];
static $customViewColumns = [
'officerLevel' => 0,
'officerLevelText' => 0,
'lbonus' => 0,
'ownerName' => 0,
'honorText' => 0,
'dedLevelText' => 0,
'bill' => 0,
'reservedCommand' => 1,
'autorun_limit' => 1,
];
public function validateArgs(): ?string
{
//TODO: 장기적으로는 요청에 따라 반환해야...
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
private function getOfficerLevel($rawGeneral)
{
$level = $rawGeneral['officer_level'];
if ($level >= 5) {
return $level;
}
if ($this->permission > 1) {
return $level;
}
return 1;
}
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag)
{
increaseRefresh("세력장수", 1);
$db = DB::db();
$gameStor = \sammo\KVStorage::getStorage($db, 'game_env');
$env = $gameStor->getValues(['year', 'month', 'turntime', 'turnterm', 'autorun_user', 'killturn']);
$me = $db->queryFirstRow('SELECT con, turntime, belong, nation, officer_level, permission, penalty FROM general WHERE owner=%i', $session->getUserID());
$con = checkLimit($me['con']);
if ($con >= 2) {
return '접속 제한중입니다. 1턴 이내에 너무 많은 갱신을 하셨습니다.';
}
$nationID = $me['nation'];
$this->permission = checkSecretPermission($me, true);
$nationArr = getNationStaticInfo($nationID);
[$queryColumns, $rankColumns] = General::mergeQueryColumn(array_keys(static::$viewColumns), 1);
$rawGeneralList = Util::convertArrayToDict($db->query('SELECT %l from general WHERE nation = %i ORDER BY turntime ASC', Util::formatListOfBackticks($queryColumns), $nationID), 'no');
$reservedCommand = [];
if ($this->permission >= 1) {
$nonNPCGeneralIDList = [];
foreach ($rawGeneralList as $rawGeneral) {
if ($rawGeneral['npc'] < 2) {
$nonNPCGeneralIDList[] = $rawGeneral['no'];
}
}
$rawTurnList = $db->query(
'SELECT general_id, turn_idx, action, arg, brief FROM general_turn WHERE general_id IN %li AND turn_idx < 5 ORDER BY general_id asc, turn_idx asc',
$nonNPCGeneralIDList
);
foreach ($rawTurnList as $rawTurn) {
[
'general_id' => $generalID,
'action' => $action,
'arg' => $arg,
'brief' => $brief,
] = $rawTurn;
if (!key_exists($generalID, $reservedCommand)) {
$reservedCommand[$generalID] = [];
}
$reservedCommand[$generalID][] = [
'action' => $action,
'arg' => $arg,
'brief' => $brief
];
}
}
$rankList = [];
if ($rankColumns) {
$rankColumns = Util::valuesFromEnumArray($rankColumns);
$rawRankList = $db->query('SELECT general_id, `type`, `value` FROM rank_data WHERE nation_id = %i AND `type` IN %ls', $nationID, $rankColumns);
foreach ($rawRankList as $rawRank) {
[
'general_id' => $generalID,
'type' => $type,
'value' => $value
] = $rawRank;
if (!key_exists($generalID, $rankList)) {
$rankList[$generalID] = [];
}
$rankList[$generalID][$type] = $value;
}
}
$getRankVar = fn ($key) => (fn ($rawGeneral) => (($rankList[$rawGeneral['no']] ?? [])[$key] ?? 0));
$specialViewFilter = [
'officerLevel' => fn ($rawGeneral) => $this->getOfficerLevel($rawGeneral),
'officerLevelText' => fn ($rawGeneral) => getOfficerLevelText($this->getOfficerLevel($rawGeneral), $nationArr['level']),
'lbonus' => fn ($rawGeneral) => calcLeadershipBonus($rawGeneral['officer_level'], $nationArr['level']),
'ownerName' => fn ($rawGeneral) => ($rawGeneral['npc'] != 1) ? null : $rawGeneral['owner_name'],
'honorText' => fn ($rawGeneral) => getHonor($rawGeneral['experience']),
'dedLevelText' => fn ($rawGeneral) => getDedLevelText($rawGeneral['dedlevel']),
//'0000-00-00 11:23';
'turntime' => fn ($rawGeneral) => substr($rawGeneral['turntime'], 0, 19),
'recent_war' => fn ($rawGeneral) => substr($rawGeneral['recent_war'], 0, 19),
'bill' => fn ($rawGeneral) => getBillByLevel($rawGeneral['dedlevel']),
'reservedCommand' => fn ($rawGeneral) => $reservedCommand[$rawGeneral['no']] ?? null,
'autorun_limit' => fn ($rawGeneral) => ($rawGeneral['aux'] ?? [])['autorun_limit'] ?? 0,
];
foreach ($rankColumns as $rankKey) {
$specialViewFilter[$rankKey] = $getRankVar($rankKey);
}
$resultColumns = [];
foreach (static::$viewColumns as $column => $reqPermission) {
if ($reqPermission > $this->permission) {
continue;
}
if (key_exists($column, static::$columnRemap)) {
$newColumn = static::$columnRemap[$column];
if ($newColumn !== null) {
$resultColumns[$newColumn] = $column;
}
} else {
$resultColumns[$column] = $column;
}
}
foreach (static::$customViewColumns as $column => $reqPermission) {
if ($reqPermission > $this->permission) {
continue;
}
$resultColumns[$column] = $column;
}
$generalList = [];
foreach ($rawGeneralList as $rawGeneral) {
//General 생성?
if (key_exists('aux', $rawGeneral)) {
$rawGeneral['aux'] = \sammo\JSON::decode($rawGeneral['aux']);
}
$item = [];
foreach ($resultColumns as $column) {
if (key_exists($column, $specialViewFilter)) {
$value = $specialViewFilter[$column]($rawGeneral);
} else {
$value = $rawGeneral[$column];
}
$item[] = $value;
}
$generalList[] = $item;
}
if ($this->permission >= 1) {
$troops = $db->queryAllLists('SELECT troop_leader,name FROM troop WHERE nation = %i', $nationID);
} else {
$troops = null;
}
$result = [
'result' => true,
'permission' => $this->permission,
'column' => array_keys($resultColumns),
'list' => $generalList,
'troops' => $troops,
'env' => $env,
];
return $result;
}
}
+166
View File
@@ -0,0 +1,166 @@
<?php
namespace sammo\API\Nation;
use sammo\DB;
use sammo\Session;
use sammo\Validator;
use function sammo\checkLimit;
use function sammo\checkSecretPermission;
use function sammo\getBattleDetailLogMore;
use function sammo\getBattleResultMore;
use function sammo\getBattleResultRecent;
use function sammo\getGeneralActionLogMore;
use function sammo\getGeneralActionLogRecent;
use function sammo\getGeneralHistoryLogAll;
class GetGeneralLog extends \sammo\BaseAPI
{
const GENERAL_HISTORY = 'generalHistory';
const GENERAL_ACTION = 'generalAction';
const BATTLE_RESULT = 'battleResult';
const BATTLE_DETAIL = 'battleDetail';
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v
->rule('required', [
'generalID',
'type',
])
->rule('integer', [
'generalID',
'reqTo',
])
->rule('in', 'type', [
self::GENERAL_HISTORY,
self::GENERAL_ACTION,
self::BATTLE_RESULT,
self::BATTLE_DETAIL,
]);
if (!$v->validate()) {
return $v->errorStr();
}
$this->args['generalID'] = (int)$this->args['generalID'];
if (key_exists('reqTo', $this->args)) {
$this->args['reqTo'] = (int)$this->args['reqTo'];
}
return null;
}
public function checkPermission(array $me): ?string
{
$permission = checkSecretPermission($me);
if ($permission < 0) {
return '국가에 소속되어있지 않습니다.';
}
$db = DB::db();
$generalID = $this->args['generalID'];
[$testGeneralNationID, $testGeneralNPCType] = $db->queryFirstList(
'SELECT nation,npc FROM general WHERE no = %i',
$generalID
);
if ($permission < 1) {
return '권한이 부족합니다. 수뇌부가 아니거나 사관년도가 부족합니다.';
}
$nationID = $me['nation'];
if ($testGeneralNationID !== $nationID) {
return '같은 나라의 장수가 아닙니다.';
}
$reqType = $this->args['type'];
if (
$reqType === self::GENERAL_ACTION &&
$testGeneralNPCType < 2 &&
$generalID !== $me['generalID'] &&
$permission < 2
) {
return '권한이 부족합니다. 유저 장수의 개인 기록은 수뇌만 열람 가능합니다.';
}
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function getTargetGeneralID(Session $session): int{
return $this->args['generalID'];
}
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$userID = $session->userID;
$targetGeneralID = $this->getTargetGeneralID($session);
$reqType = $this->args['type'];
$reqTo = $this->args['reqTo'] ?? null;
$db = DB::db();
$me = $db->queryFirstRow('SELECT no,nation,officer_level,con,turntime,belong,permission,penalty from general where owner=%i', $userID);
$con = checkLimit($me['con']);
if ($con >= 2) {
return '접속 제한입니다.';
}
$permissionResult = $this->checkPermission($me);
if ($permissionResult !== null) {
return $permissionResult;
}
if ($reqType == static::GENERAL_HISTORY) {
return [
'result' => true,
'reqType' => $reqType,
'generalID' => $targetGeneralID,
'log' => getGeneralHistoryLogAll($targetGeneralID)
];
}
if ($reqType == static::GENERAL_ACTION) {
return [
'result' => true,
'reqType' => $reqType,
'generalID' => $targetGeneralID,
'log' => $reqTo === null
? getGeneralActionLogRecent($targetGeneralID, 30)
: getGeneralActionLogMore($targetGeneralID, $reqTo, 30)
];
}
if ($reqType == static::BATTLE_RESULT) {
return [
'result' => true,
'reqType' => $reqType,
'generalID' => $targetGeneralID,
'log' => $reqTo === null
? getBattleResultRecent($targetGeneralID, 30)
: getBattleResultMore($targetGeneralID, $reqTo, 30)
];
}
if ($reqType == static::BATTLE_DETAIL) {
return [
'result' => true,
'reqType' => $reqType,
'generalID' => $targetGeneralID,
'log' => $reqTo === null
? getBattleResultRecent($targetGeneralID, 30)
: getBattleDetailLogMore($targetGeneralID, $reqTo, 30)
];
}
return '잘못된 요청입니다: ' . $reqType;
}
}
+1 -1
View File
@@ -47,7 +47,7 @@ class SetBlockScout extends \sammo\BaseAPI
return "권한이 부족합니다.";
}
$gameStor = new KVStorage($db, 'game_env');
$gameStor = KVStorage::getStorage($db, 'game_env');
$blockChangeScout = $gameStor->getValue('block_change_scout')??false;
if ($blockChangeScout){
return "임관 설정을 바꿀 수 없도록 설정되어 있습니다.";
@@ -13,9 +13,7 @@ use sammo\TimeUtil;
use function sammo\checkLimit;
use function sammo\checkSecretPermission;
use function sammo\cutTurn;
use function sammo\getChiefCommandTable;
use function sammo\getNationChiefLevel;
use function sammo\getOfficerLevelText;
use function sammo\increaseRefresh;
@@ -117,6 +115,8 @@ class GetReservedCommand extends \sammo\BaseAPI
'autorun_limit' => $generalObj->getAuxVar('autorun_limit'),
'officerLevel' => $me['officer_level'],
'commandList' => getChiefCommandTable($generalObj),
'mapName' => GameConst::$mapName,
'unitSet' => GameConst::$unitSet,
];
}
}
@@ -7,7 +7,6 @@ use DateTimeInterface;
use sammo\DB;
use sammo\Validator;
use function sammo\cutTurn;
use function sammo\pushNationCommand;
class PushCommand extends \sammo\BaseAPI
@@ -7,8 +7,6 @@ use DateTimeInterface;
use sammo\DB;
use sammo\Validator;
use function sammo\cutTurn;
use function sammo\repeatGeneralCommand;
use function sammo\repeatNationCommand;
class RepeatCommand extends \sammo\BaseAPI
@@ -0,0 +1,76 @@
<?php
namespace sammo\API\NationCommand;
use sammo\Session;
use DateTimeInterface;
use sammo\GameConst;
use sammo\Util;
use sammo\Validator;
use function sammo\setNationCommand;
class ReserveBulkCommand extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
foreach ($this->args as $idx => $turn) {
$v = new Validator($turn);
$v->rule('required', [
'action',
'turnList'
])
->rule('lengthMin', 'action', 1)
->rule('integerArray', 'turnList');
if (!$v->validate()) {
return "{$idx}:{$v->errorStr()}";
}
}
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
{
$briefList = [];
foreach ($this->args as $idx => $turn) {
$action = $turn['action'];
$turnList = $turn['turnList'];
$arg = $turn['arg'] ?? [];
if (!$turnList) {
return "{$idx}: 턴이 입력되지 않았습니다";
}
if (!in_array($action, Util::array_flatten(GameConst::$availableChiefCommand))) {
return "{$idx}: 사용할 수 없는 커맨드입니다.";
}
if (!is_array($arg)) {
return "{$idx}: 올바른 arg 형태가 아닙니다.";
}
$partialResult = setNationCommand($session->generalID, $turnList, $action, $arg);
if(!$partialResult['result']){
return [
'result' => false,
'briefList' => $briefList,
'errorIdx' => $idx,
'reason' => $partialResult['reason']
];
}
$briefList[$idx] = $partialResult['brief'];
}
return [
'result' => true,
'briefList' => $briefList,
'reason' => 'success'
];
}
}
+4 -3
View File
@@ -13,7 +13,7 @@ class che_보물_도기 extends \sammo\BaseItem
protected $rawName = '도기';
protected $name = '도기(보물)';
protected $info = '[개인] 판매 시 국고에 금, 쌀 중 하나를 추가 (+10,000, 5년마다 +10,000)';
protected $info = '[개인] 판매 시 장수 소지금과 국고에 금, 쌀 중 하나를 추가 (+10,000, 5년마다 +10,000)';
protected $cost = 200;
protected $consumable = false;
@@ -48,15 +48,16 @@ class che_보물_도기 extends \sammo\BaseItem
if ($nationId != 0) {
$db->update('nation', [
$resKey => $db->sqleval('%b + %i', $resKey, $score)
$resKey => $db->sqleval('%b + %i', $resKey, Util::toInt($score / 2))
], 'nation=%i', $nationId);
}
$general->increaseVar($resKey, $score - Util::toInt($score / 2));
$score = Util::round($score);
$scoreText = number_format($score, 0);
$logger = $general->getLogger();
$logger->pushGeneralActionLog("국고에 {$resName} <C>{$scoreText}</>을 보충합니다.");
$logger->pushGeneralActionLog("재산과 국고에 {$resName} <C>{$scoreText}</>을 보충합니다.");
return $aux;
}
}
@@ -10,7 +10,7 @@ class che_상성보정_과실주 extends \sammo\BaseItem{
protected $rawName = '과실주';
protected $name = '과실주(상성)';
protected $info = '[전투] 유리한 병종 전투시 공격력 +10%, 피해 -10%';
protected $info = '[전투] 대등/유리한 병종 전투시 공격력 +10%, 피해 -10%';
protected $cost = 200;
protected $consumable = false;
@@ -18,7 +18,7 @@ class che_상성보정_과실주 extends \sammo\BaseItem{
{
$oppose = $unit->getOppose();
$attackCoef = $unit->getCrewType()->getAttackCoef($oppose->getCrewType());
if($attackCoef <= 1){
if($attackCoef < 1){
return null;
}
return new WarUnitTriggerCaller(
@@ -13,7 +13,7 @@ class che_의술_상한잡병론 extends \sammo\BaseItem{
protected $rawName = '상한잡병론';
protected $name = '상한잡병론(의술)';
protected $info = '[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복<br>[전투] 페이즈마다 40% 확률로 치료 발동(아군 피해 1/3 감소, 부상 회복)';
protected $info = '[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복<br>[전투] 페이즈마다 40% 확률로 치료 발동(아군 피해 30% 감소, 부상 회복)';
protected $cost = 200;
protected $consumable = false;
@@ -13,7 +13,7 @@ class che_의술_정력견혈산 extends \sammo\BaseItem{
protected $rawName = '정력견혈산';
protected $name = '정력견혈산(의술)';
protected $info = '[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복<br>[전투] 페이즈마다 40% 확률로 치료 발동(아군 피해 1/3 감소, 부상 회복)';
protected $info = '[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복<br>[전투] 페이즈마다 40% 확률로 치료 발동(아군 피해 30% 감소, 부상 회복)';
protected $cost = 200;
protected $consumable = false;
@@ -13,7 +13,7 @@ class che_의술_청낭서 extends \sammo\BaseItem{
protected $rawName = '청낭서';
protected $name = '청낭서(의술)';
protected $info = '[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복<br>[전투] 페이즈마다 40% 확률로 치료 발동(아군 피해 1/3 감소, 부상 회복)';
protected $info = '[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복<br>[전투] 페이즈마다 40% 확률로 치료 발동(아군 피해 30% 감소, 부상 회복)';
protected $cost = 200;
protected $consumable = false;
@@ -13,7 +13,7 @@ class che_의술_태평청령 extends \sammo\BaseItem{
protected $rawName = '태평청령';
protected $name = '태평청령(의술)';
protected $info = '[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복<br>[전투] 페이즈마다 40% 확률로 치료 발동(아군 피해 1/3 감소, 부상 회복)';
protected $info = '[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복<br>[전투] 페이즈마다 40% 확률로 치료 발동(아군 피해 30% 감소, 부상 회복)';
protected $cost = 200;
protected $consumable = false;
@@ -27,7 +27,7 @@ class che_치트_HideD의_사인검 extends \sammo\BaseItem
protected $info = <<<EOT
통솔 +100,무력 +100, 지력 +100<br>
[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복<br>
[전투] 페이즈마다 20% 확률로 치료 발동(아군 피해 1/3 감소)<br>
[전투] 페이즈마다 20% 확률로 치료 발동(아군 피해 30% 감소)<br>
[전투] 새로운 상대와 전투 시 1/2 확률로 저격 발동, 성공 시 사기+20<br>
[전투] 훈련 보정 +30, 사기 보정 +30<br>
[전투] 상대방 필살 및 회피 시도시 일정 확률로 격노(필살) 발동, 공격 시 일정 확률로 진노(1페이즈 추가)<br>
@@ -1,5 +1,7 @@
<?php
namespace sammo\ActionItem;
use sammo\Enums\RankColumn;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
@@ -30,7 +32,7 @@ class event_전투특기_무쌍 extends \sammo\BaseItem{
}
$attackMultiplier = 1.05;
$defenceMultiplier = 0.98;
$killnum = $unit->getGeneral()->getRankVar('killnum');
$killnum = $unit->getGeneral()->getRankVar(RankColumn::killnum);
$attackMultiplier += log(max(1, $killnum / 5), 2) / 20;
$defenceMultiplier -= log(max(1, $killnum / 5), 2) / 50;
return [$attackMultiplier, $defenceMultiplier];
@@ -15,7 +15,7 @@ class event_전투특기_의술 extends \sammo\BaseItem{
protected $rawName = '비급';
protected $name = '비급(의술)';
protected $info = '[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복<br>[전투] 페이즈마다 40% 확률로 치료 발동(아군 피해 1/3 감소, 부상 회복)';
protected $info = '[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복<br>[전투] 페이즈마다 40% 확률로 치료 발동(아군 피해 30% 감소, 부상 회복)';
protected $cost = 100;
protected $buyable = true;
protected $consumable = false;
@@ -1,5 +1,7 @@
<?php
namespace sammo\ActionSpecialDomestic;
use sammo\Enums\RankColumn;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
@@ -32,7 +34,7 @@ class che_event_무쌍 extends \sammo\BaseSpecial{
}
$attackMultiplier = 1.05;
$defenceMultiplier = 0.98;
$killnum = $unit->getGeneral()->getRankVar('killnum');
$killnum = $unit->getGeneral()->getRankVar(RankColumn::killnum);
$attackMultiplier += log(max(1, $killnum / 5), 2) / 20;
$defenceMultiplier -= log(max(1, $killnum / 5), 2) / 50;
return [$attackMultiplier, $defenceMultiplier];

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