Compare commits

...
233 Commits
Author SHA1 Message Date
Hide_D 83d6a2169b 유산 포인트 시스템, 추가 기수 대비 (#187)
- 유산 포인트
  - 기수 뒤로도 누적되는 포인트
  - 생존, 최대 임관년 수, 최대 연속 내정 성공, 병종 상성 우위 횟수, 전투 횟수, 계략 성공 횟수, 천통 기여(규모 상승, 천통 수뇌, 천통 군주), 숙련도, 토너먼트, 베팅 당첨
  - 유산 관리 페이지 제공

- 태수국
  - 181년 1월에 자동 생성되는 u장수국
  - 시간이 지나면 사실상 자동 소멸
  - 유저국과는 4칸 거리, 서로는 2칸 거리
  - 이 시스템으로 인해 m장 거병 차단

- NPC 원조시 불가침
  - 1년 세수만큼 받은 경우 24개월 불가침 제안
  - 최소 6개월
  - 불가침을 받지 않고 추가 원조한 경우 계속해서 기간 상승
  - 단, 불가침 수락 전에 선포를 할 수 있음

Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/187
Co-authored-by: hide_d <hided62@gmail.com>
Co-committed-by: hide_d <hided62@gmail.com>
2021-08-11 21:57:52 +09:00
Hide_D 21e7a4d966 Dep: update
주로 PHAN
2021-08-06 22:39:09 +09:00
Hide_D 404cd24855 작위보상 비중 수정 2021-05-02 02:00:16 +09:00
Hide_D b4ad72ee67 환약을 유니크로 습득하는 버그 수정 2021-05-01 23:48:01 +09:00
Hide_D bea628b619 환약을 습득하게 되는 버그 수정 2021-05-01 23:46:33 +09:00
Hide_D 3637e54982 유니크 onCalcStat 버그 수정 2021-05-01 23:38:06 +09:00
Hide_D e0d1a0a612 아이템 효과 텍스트 수정 2021-04-30 22:36:24 +09:00
Hide_D 3040996671 무쌍 누락분 수정 2021-04-30 16:35:34 +09:00
Hide_D dd830e7500 TypeCode 추가 2021-04-29 22:38:46 +09:00
Hide_D d2dfe2c418 전투 수비 파트 약 상향 2021-04-29 21:10:47 +09:00
Hide_D 139fb6b6e0 국가 규모 승급시 아이템 습득 방식 변경 2021-04-29 20:31:32 +09:00
Hide_D c4f6976c42 유니크 아이템에 효과 추가 2021-04-29 19:50:12 +09:00
Hide_D ab428fc104 유니크 기본 획득 확률 변경 2021-04-29 18:49:19 +09:00
Hide_D aa97f78acd 무쌍 초반 버프, 후반 너프 2021-04-29 18:47:55 +09:00
Hide_D dbce900aeb 유니크 중복 획득 가능 2021-04-29 18:44:09 +09:00
Hide_D 30b382e2e7 초반 등록 NPC 30명 2021-04-29 18:30:46 +09:00
Hide_D 433c4abb86 fix: 이민족 종료 시점 2021-04-11 23:17:47 +09:00
Hide_D 64404e4092 fix: 이민족 종료조건 추가 2021-04-11 21:22:06 +09:00
Hide_D 08d483af8a fix: 후방 워프 인구 충분 판단 기준 수정 2021-04-10 16:01:21 +09:00
Hide_D fa19c17941 fix: AI 발령 턴 오류 수정 2021-04-10 15:39:03 +09:00
Hide_D c896a999ad fix: 전방 도시가 '관'처럼 인구가 적은 경우 후방 워프하지 않는 버그 수정
feat: 후방 발령 관련 로직도 후방 워프와 유사하게 재 적용
2021-04-10 11:51:10 +09:00
Hide_D f9bca935ac fix: 장수수 카운트에 "의병장"을 포함하여 계산하는 버그 수정 2021-04-02 14:39:57 +09:00
Hide_D 7abf274d89 이민족 난이도 기본 수치 변경 2021-03-29 22:45:43 +09:00
Hide_D e2ad417306 feat: 이민족 등장 2021-03-28 16:31:01 +09:00
Hide_D 2ea9655f6b fix: 이민족 2021-03-28 05:57:53 +09:00
Hide_D f450d5d9de fix: 수비자 도시 버그
fix: RaiseInvader 버그 수정 중
2021-03-28 04:12:10 +09:00
Hide_D f8f4b73a09 feat: RaiserInvader 초기 구현 2021-03-28 03:13:03 +09:00
Hide_D 926d96732d fix: 가상 역사 모드에서 후계자 지정이 사실 모드 설정을 따라가는 버그 수정 2021-03-23 13:24:34 +09:00
Hide_D 167113d6a3 fix: 빙의 해제시 owner 값 버그 수정 2021-03-23 13:19:40 +09:00
Hide_D 911cb614a5 fix: RegNPC 버그 수정, event handler 규격 버그 수정 2021-03-19 18:09:53 +09:00
Hide_D 7a939b7024 fix: RegNPC 버그 수정 2021-03-19 17:44:34 +09:00
Hide_D 6e57a60997 RegNPC 버그 수정 2021-03-19 17:36:13 +09:00
Hide_D 9f1151e699 fix: can부대구출발령 없음 2021-03-19 17:22:48 +09:00
Hide_D 3fbe1fb63d 디버그2 2021-02-28 01:39:47 +09:00
Hide_D d4906eec5a 디버그 코드 추가 2021-02-28 01:33:58 +09:00
Hide_D ebe0663e74 에러 로그용 추가 2021-02-28 01:05:27 +09:00
Hide_D 04c89b9711 긴급 호출 대비 2021-02-21 00:40:49 +09:00
Hide_D 4f2bc874e5 initFull을 할 필요가 없었던 것! 2021-02-10 21:24:04 +09:00
Hide_D 316ac5c3c8 불가침인데도 선포 가능한 버그 수정 2021-01-12 17:14:36 +09:00
Hide_D 7882aa667e 관리자 도구 수정 2021-01-07 22:22:04 +09:00
Hide_D 8b8d5eecbf 모반시도 버그 수정 2021-01-07 01:12:06 +09:00
Hide_D 65b76643ee feat: 빙의일람에 장수 선택 내역
fix: 장수 선택 내역에서 owner_name 미반영 버그 수정
fix: 온라인 장수에서 npc가 뜨는 버그 수정
2021-01-03 18:31:18 +09:00
Hide_D f33e645113 초반 m장 스탯 관련 문제 해결, 장수 선택 term 해결 2021-01-01 21:09:43 +09:00
Hide_D 528d30c317 의병모집 버그 수정 2021-01-01 19:56:29 +09:00
Hide_D 7f0a3d320c 버그 수정
- 의병 모집
- 장수 변경 시 생성 폼 남음
2021-01-01 19:54:28 +09:00
Hide_D 8e940aeb65 버그 수정. 시간 변경 2020-12-31 16:21:57 +09:00
Hide_D a77ee60809 버그.. 2020-12-31 13:34:37 +09:00
Hide_D 83383c29cd 버그 수정2 2020-12-31 13:33:45 +09:00
Hide_D b6393141e8 버그 수정 2020-12-31 13:29:57 +09:00
Hide_D 10ce1827d8 버그 수정 2020-12-31 13:27:11 +09:00
Hide_D 605f3a12ff select pool 수 증가 2020-12-31 13:24:33 +09:00
Hide_D a33539e75f 턴 변경을 합리적으로 변경 2020-12-31 08:09:23 +09:00
Hide_D b2cca3687a 버그 수정 2020-12-31 07:49:33 +09:00
Hide_D 628c54044f general_pool 에서 장수 선택 기능 추가 2020-12-31 07:43:56 +09:00
Hide_D c0e7a3eece readme 수정 2020-12-27 19:49:39 +09:00
Hide_D c7c13c19c1 일부 수정
composer update, README.md 업데이트
2020-12-27 02:11:53 +09:00
Hide_D d5f71b5878 DummySession 준비 2020-12-26 15:48:05 +09:00
Hide_D cb589e9e26 종전수락 버그 수정 2020-12-13 22:05:07 +09:00
Hide_D eaeed47297 도시 정보 출력 순서 변경 2020-11-11 23:34:53 +09:00
Hide_D e00e5c5cd7 이벤트 빼빼로 추가 2020-11-11 23:04:08 +09:00
Hide_D b3719f7166 수극 연속 사용 버그 수정 2020-09-09 14:20:15 +09:00
Hide_D 337896974b 피장파장 로그 버그 수정 2020-09-09 14:20:15 +09:00
Hide_D bb7d1fc9ab 수몰을 아무 국가에나 쓸 수 있는 버그 수정 2020-09-09 14:20:15 +09:00
Hide_D 07765c8d44 훈사 제한 버그 2020-08-17 09:21:37 +09:00
Hide_D 85cb91071e 기본 도시 정보 데이터 대폭 추가 2020-08-15 03:46:43 +09:00
Hide_D d41839845a 귀병 첫 페이즈 매우 높은 확률로 계략 시도 2020-08-11 22:43:45 +09:00
Hide_D c3d12aa55f 전쟁/선포 중인 국가에 선포 확률 대폭 감소 2020-08-11 22:36:26 +09:00
Hide_D a781e4b84c 인탐 성공 시 확률따라 추가 보정, 인탐/의병 지장 버그 수정 2020-08-11 22:33:50 +09:00
Hide_D 1fc0989fd2 계략 강화, 탈취량 시간에 따라 증가 2020-08-11 22:33:00 +09:00
Hide_D 14752260d3 회피 필살 중첩 가능 2020-07-24 14:19:05 +09:00
Hide_D 84675c874f 이호경식 버그 수정 2020-07-21 22:38:53 +09:00
Hide_D f30e6057be 버그 테스트 2020-07-21 22:34:10 +09:00
Hide_D ba8b629f0e 격노비급 버그 수정 2020-07-21 03:41:27 +09:00
Hide_D a0a45ff2aa 격노 비급 버그 수정 2020-07-21 03:32:37 +09:00
Hide_D 325f890a0b 방랑시 버그 수정 2020-07-20 23:24:15 +09:00
Hide_D 923cac5408 전략 턴 버그 수정. 글로벌 쿨 9턴으로 변경 2020-07-17 00:16:48 +09:00
Hide_D 23505326c7 격노 추가 향상 2020-07-16 02:57:37 +09:00
Hide_D 5f1a48f523 아이템 짝 안맞는 것 수정 2020-07-16 02:38:40 +09:00
Hide_D a607d39030 아이템 수정 2020-07-16 02:31:18 +09:00
Hide_D 96d108729e 위압 사기버그 수정 2020-07-15 11:55:35 +09:00
Hide_D ef15adaaf8 저격 약간 더 강화 2020-07-15 02:56:31 +09:00
Hide_D f190b74a7e 필살 조금 더 강화 2020-07-15 02:52:14 +09:00
Hide_D edbc2b88b6 버그 수정 2020-07-15 02:43:00 +09:00
Hide_D dc000cecf1 전특 대 개편 2020-07-15 02:33:21 +09:00
Hide_D 7c95a483df 기본 스탯 향상 2020-07-13 23:25:33 +09:00
Hide_D 27e5d73da1 전략별 쿨타임 적용 2020-07-13 23:21:21 +09:00
Hide_D 6306dae92d 전략 사용 방식 변경 2020-07-13 21:54:32 +09:00
Hide_D a427ddff83 수동 토너먼트 버그 수정 2020-07-07 15:24:48 +09:00
Hide_D b62ee6e820 버그 수정 2020-06-26 23:33:39 +09:00
Hide_D 3c18666080 로그인 form draw 예시 2020-06-26 23:31:45 +09:00
Hide_D 40968b301a file_cache_준비 2020-06-26 21:24:24 +09:00
Hide_D 05904d31fd webp 지원 2020-06-26 02:43:46 +09:00
Hide_D 75aeaf4ee7 후방워프 버그 수정 2020-06-26 02:30:35 +09:00
Hide_D ff4e67a9f6 중립턴, 내정워프 수정 2020-06-26 02:26:59 +09:00
Hide_D 5f672d5bd1 몰수 기준 완화 2020-06-26 00:16:56 +09:00
Hide_D 5cb39eba8b 전특 초기화에서 '쿨'을 감안함 2020-06-25 23:45:09 +09:00
Hide_D 4d8c3c75d6 새 금쌀 구매 로직 2020-06-25 23:43:35 +09:00
Hide_D 8bdd19fc06 버그 수정 2020-06-21 17:07:03 +09:00
Hide_D 0ec99d8ba1 서버 커스터마이징 가능 2020-06-21 17:03:32 +09:00
Hide_D 929d2db5a5 유저장 구출 버그 수정 예상 2020-06-20 21:43:28 +09:00
Hide_D a7ad77f433 최근 전투 페이즈 계산 버그 수정 2020-06-20 15:09:35 +09:00
Hide_D 9cd47d5deb recent_war 표기 방식 변경경 2020-06-19 20:24:50 +09:00
Hide_D 3cb5691aae 수비 기호 표시 추가 2020-06-18 01:05:34 +09:00
Hide_D dce63919fa 부대유저장발령 코드 일부 수정 2020-06-17 03:39:22 +09:00
Hide_D 1cdbedcb96 도시 치료 결과가 이상하게 뜨는 버그 수정 2020-06-16 00:26:45 +09:00
Hide_D 1586712ce5 버그 수정 2020-06-12 22:11:19 +09:00
Hide_D f059186494 구출 발령 활성화 안된 버그 수정 2020-06-12 22:08:56 +09:00
Hide_D 0af0be57b0 전방 발령 버그 수정 2020-06-12 21:16:37 +09:00
Hide_D dad2b03212 ExistsDestNation 버그 수정 2020-06-12 20:39:31 +09:00
Hide_D b6e307660f warning 수정 2020-06-12 20:28:50 +09:00
Hide_D c21c14825a 오타 수정 2020-06-11 03:28:10 +09:00
Hide_D 39f9c986e9 버그 수정 2020-06-11 03:21:26 +09:00
Hide_D 393683aebc 버그 수정 2020-06-11 03:14:12 +09:00
Hide_D a87fcb44a6 전투 시뮬레이터 장수 불러오기 완성 2020-06-11 03:13:02 +09:00
Hide_D 0a6496ddfb 관직 비우기 안되는 것 수정 2020-06-11 00:29:36 +09:00
Hide_D fa2841fac6 원조 버그 수정 2020-06-11 00:20:08 +09:00
Hide_D 861e45419b 포상 검사 로직 빠진 부분 수정 2020-06-09 20:50:57 +09:00
Hide_D 15fd943456 전쟁장 판단 기준 임시 수정, 사망 대비 장수에겐 포상안함 2020-06-09 20:32:49 +09:00
Hide_D b538bfc27e Merge branch 'devel' of ssh://storage.hided.net:2525/devsam/core into devel 2020-06-09 20:30:41 +09:00
Hide_D e0f32eddc4 전쟁장 판별 코드 임시 수정 2020-06-09 20:30:34 +09:00
Hide_D 75a704c196 저격시 아이템이 무조건 소모되는 버그 수정 2020-06-09 01:45:52 +09:00
Hide_D 6565fdbe7e 무장 신산 가능 2020-06-09 01:25:35 +09:00
Hide_D 6248d72852 홀짝 버그 수정 2020-06-09 01:10:21 +09:00
Hide_D 00d1797b96 내특 동작 안하는 버그 수정 2020-06-09 01:03:58 +09:00
Hide_D 911194eba8 찐유저무쌍 비급판 2020-06-07 16:08:04 +09:00
Hide_D 0fad3ae31d 유지비를 깎고 세수를 계산하도록 수정 2020-06-06 19:21:51 +09:00
Hide_D b6988d866a 선포 동안에는 초토화 가능하도록 수정 2020-06-06 15:43:29 +09:00
Hide_D e30959a656 숙련전환 효율 향상 2020-06-06 14:33:21 +09:00
Hide_D 52eeff3466 환약 사용 여부가 안보이는 버그 수정 2020-06-06 13:45:31 +09:00
Hide_D a06ded552d 유저장은 자동 사령턴 켬끔 가능 2020-06-06 13:20:01 +09:00
Hide_D e9b8a84243 전방 발령에 공백지 배제 2020-06-06 12:55:34 +09:00
Hide_D 1fc3cfd1f2 중립 인탐 확률 감소 2020-06-06 03:07:00 +09:00
Hide_D 188b57ed7a 랜덤 임관 버그 수정 2020-06-05 18:13:21 +09:00
Hide_D c8620390ac 중립 커맨드 2020-06-05 02:25:44 +09:00
Hide_D b3f8ed2335 지도 기반 선택 버그 수정 2020-06-05 01:14:49 +09:00
Hide_D 54bf504eb4 명령 입력턴에 select2 적용 2020-06-05 01:02:33 +09:00
Hide_D c6f3bf856b select2 업그레이드 2020-06-04 23:21:47 +09:00
Hide_D 8b33a7926e 오호 장군 수정 2020-06-04 21:31:26 +09:00
Hide_D a38cb90cbf 천지비급 시나리오를 설명에 맞게 수정 2020-06-03 22:17:22 +09:00
Hide_D 1500e8e54f 서버가 닫힌 경우 리다이렉트하도록 2020-06-03 01:51:31 +09:00
Hide_D 94fd8d5e9d 세력도시 암행부 연동 버그 수정 2020-06-02 01:24:25 +09:00
Hide_D 373e0a2155 버그 수정 시도2 2020-06-02 01:06:00 +09:00
Hide_D 267298f341 사령부 공백이어도 사령턴은 보임 2020-06-02 00:24:44 +09:00
Hide_D 359d46e94d 천지비급 디버그 풀기 2020-06-02 00:08:52 +09:00
Hide_D 11f5540099 composer 반영 2020-06-01 21:14:50 +09:00
Hide_D 680e1afcfd 버그 수정 2020-06-01 02:34:56 +09:00
Hide_D e4322e60cc 환약 사용 기준 추가 2020-06-01 02:31:46 +09:00
Hide_D 82f2eecfe8 내 설정 페이지 동작 방식 일단 수정 2020-06-01 02:17:20 +09:00
Hide_D 3e3c3c559d 소모성 아이템 소비 2020-05-31 23:11:17 +09:00
Hide_D 65f5e8e964 setResultTurn 버그 수정 2020-05-31 17:21:51 +09:00
Hide_D c5fbe93890 버그 수정 2020-05-31 04:43:15 +09:00
Hide_D 307d8b6165 버그 수정 2020-05-31 04:42:11 +09:00
Hide_D bf08eb2f8b 버그 수정 2020-05-31 04:32:46 +09:00
Hide_D a569c1dfaf 버그 수정 2020-05-31 04:25:36 +09:00
Hide_D e48db0d231 장수 목록 json 버그 수정 2020-05-31 04:12:42 +09:00
Hide_D 1a5b5dbb45 격노 1회만 2020-05-31 01:47:44 +09:00
Hide_D 56f21cabe5 격노 발동은 1회만 2020-05-31 01:44:44 +09:00
Hide_D 7ac5afe05b 이벤트 특기 버그 수정 2020-05-30 22:50:48 +09:00
Hide_D b3db97f4a8 이중특기 테스트 2020-05-30 16:31:03 +09:00
Hide_D 6d1a06a9d9 긴급 쌀 시 병량패퇴를 당하지 않기 위해 강제 회피 2020-05-30 04:48:33 +09:00
Hide_D 088643df6c 워프 버그 수정 2020-05-30 04:41:47 +09:00
Hide_D fc00a0a363 의병모집, 소형b 초기 m장, 작위보상금쌀
의병모집 -> 초기 금쌀 1000
작위보상 -> 작위에 따라 금쌀*1000
소형b -> 초기 m장 10 추가
2020-05-30 04:36:42 +09:00
Hide_D 7a48fdd246 멸망시 임관 확률을 변경 가능하도록 설정 2020-05-30 03:18:23 +09:00
Hide_D 89be493882 인재탐색 변경. 영입 불가, 재야 가능 2020-05-30 03:09:48 +09:00
Hide_D 5947abf83d 대인 사살, 점령률 추가 2020-05-30 03:05:03 +09:00
Hide_D 962db6821f 대인살상률, 점령수 준비 2020-05-30 02:29:46 +09:00
Hide_D f6a3df7858 수비 켬끔 다양화 2020-05-30 02:08:16 +09:00
Hide_D 090aaed3f4 숙련 전환 효율 향상 2020-05-30 01:56:31 +09:00
Hide_D 71cb5aa9e4 성벽에 닳는 내정을 1/2 2020-05-29 19:16:24 +09:00
Hide_D 043b29ef33 격노 회피 시도 캔슬 2020-05-28 01:39:14 +09:00
Hide_D d81cf4aec3 소집해제 위치 이동 2020-05-28 01:33:27 +09:00
Hide_D 7cb46eeb82 Merge branch 'devel' of ssh://storage.hided.net:2525/devsam/core into devel 2020-05-26 21:44:22 +09:00
Hide_D c3b4d54414 내정 워프 버그 수정 2020-05-26 21:44:03 +09:00
Hide_D 8b9acf2d3d 실패 메시지 수정 2020-05-26 10:44:55 +09:00
Hide_D 08548181ed 첩보 가격이 저렴한 버그 수정 2020-05-26 00:47:42 +09:00
Hide_D 45f883c98b 징병창 병력 키보드 입력 버그 2020-05-25 23:28:16 +09:00
Hide_D 5f39229e47 치안강화 만땅 채우기 2020-05-24 22:52:56 +09:00
Hide_D 8c5bdc2a4b 사망시 수명 계산 버그 2020-05-24 13:41:52 +09:00
Hide_D 7b7602bce2 사령부 확실히 엔터 2020-05-23 17:21:07 +09:00
Hide_D a145792fac 헌납 비율 수정 2020-05-23 16:35:33 +09:00
Hide_D 667a550f4c 조사 수정 2020-05-23 16:30:10 +09:00
Hide_D 53e1ad8991 헌납 메시지 수정 2020-05-23 16:28:21 +09:00
Hide_D 429c949d1f AI 치안 버그 수정 2020-05-23 16:24:18 +09:00
Hide_D 1548577d65 주민선정을 매우 열심히 합니다. 2020-05-23 15:33:10 +09:00
Hide_D 82e59b297f 증축 버그 수정 2020-05-23 11:12:10 +09:00
Hide_D 1f9c994425 사령부 시간 표기 문제 2020-05-22 00:24:52 +09:00
Hide_D fc0c7a5004 호황, 풍작 색상 변경 2020-05-22 00:17:24 +09:00
Hide_D a2d0309c79 내특 중복 버그 수정 2020-05-21 12:52:00 +09:00
Hide_D 6d01fbb6e8 generalCommand 생성이 preprecessCommand보다 빠른 문제 수정 2020-05-21 12:14:46 +09:00
Hide_D be270df088 요양 입력하면 템치료 무효화 2020-05-21 02:16:20 +09:00
Hide_D 88fd94e1cc 왕조일람 국가 타입 버그 수정 2020-05-20 01:35:11 +09:00
Hide_D e460392368 인사부 임명시 색상 2020-05-20 01:31:26 +09:00
Hide_D 249cda99f4 랜덤임관에 긍정적인 메시지 추가 2020-05-20 01:26:28 +09:00
Hide_D 327fce822a Merge branch 'devel' of ssh://storage.hided.net:2525/devsam/core into devel 2020-05-20 01:11:41 +09:00
Hide_D 58931354a4 NPC 포상룰 변경 2020-05-20 01:11:35 +09:00
Hide_D c8993e9832 암해부 정렬 버그 2020-05-19 16:53:20 +09:00
Hide_D 4ee2e023aa 버그 수정 2020-05-19 10:07:24 +09:00
Hide_D 22fa1b121e 수정시도2 2020-05-19 00:32:52 +09:00
Hide_D cbc6e526c3 수정시도2 2020-05-19 00:32:40 +09:00
Hide_D 96041faefd 수정시도1 2020-05-19 00:30:55 +09:00
Hide_D 894c912e19 수정시도 1 2020-05-19 00:29:24 +09:00
Hide_D 7b406a945f 버그 수정 2020-05-19 00:25:41 +09:00
Hide_D 6ff5cc90f1 버그 수정 2020-05-19 00:18:45 +09:00
Hide_D f66e56f4b5 보궁기귀 전특 중 '통장'에 타 능력치 금지 추가 2020-05-19 00:08:50 +09:00
Hide_D 8f09aab0ea NPC 자원 기준 대폭 변경 2020-05-18 23:49:13 +09:00
Hide_D b248b9ca2c 불가침 하나만 있어도 계략이 안들어가는 버그 수정 2020-05-18 23:25:53 +09:00
Hide_D 5a6a31fefa 정착장려, 주민선정 색상 문제 2020-05-18 23:24:17 +09:00
Hide_D 1e485a3883 onCalcNationalIncome 버그 2020-05-18 23:17:16 +09:00
Hide_D fed3246c84 계략 성공시 대미지 없는 문제 수정 2020-05-18 20:12:57 +09:00
Hide_D daff4a9786 징병시 부상을 무시하는 버그 수정 2020-05-18 19:35:41 +09:00
Hide_D 6e88b0c701 로그에 도시 추가 2020-05-18 14:30:39 +09:00
Hide_D 808f674173 버그 수정? 2020-05-18 09:55:00 +09:00
Hide_D ba377c9aac 등용 UI 버그 수정 2020-05-17 20:07:09 +09:00
Hide_D bb8909f552 등용 UI 버그 수정 2020-05-17 20:05:47 +09:00
Hide_D 5a4d9ffcfc 등용장 버그 수정
등용장 초반에도 보낼 수 있도록,
리스트에서 optgroup 작성 실수
2020-05-17 20:00:06 +09:00
Hide_D 5ed24a98cb npc 정책 UI 수정 2020-05-17 19:48:20 +09:00
Hide_D 6d17675ee7 npc 정책 UI
?가 아니라 본체를 선택해도 보이도록
2020-05-17 19:45:18 +09:00
Hide_D e0b8bfdeae 버그 수정 2020-05-17 18:15:02 +09:00
Hide_D 0db2009e65 NPC 생성시 스케일러 제거 2020-05-17 13:47:28 +09:00
Hide_D 5f016d74a1 버그 수정 2020-05-17 03:03:04 +09:00
Hide_D 02b9832750 npcMax 추가 감소 2020-05-16 21:12:09 +09:00
Hide_D 18a888b9d4 인탐, 의병모집 수정, npcMin, npcTotal 추가 2020-05-16 18:59:10 +09:00
Hide_D 7f20e981d2 오호장군 표기기준 버그 수정 2020-05-16 18:16:52 +09:00
Hide_D d64e08f3c4 부대장후방발령버그 2020-05-16 16:24:45 +09:00
Hide_D 8bb5324896 출병 경로 설정 메시지 버그 수정 2020-05-16 14:14:13 +09:00
Hide_D 8f2ebc6409 인재탐색 연령버그 수정 2020-05-16 12:37:13 +09:00
Hide_D 371318f62f 버그 수정 2020-05-15 21:59:10 +09:00
Hide_D 6e94403dc6 수치 버그 수정 2020-05-15 21:51:29 +09:00
Hide_D c35f6905bb 초토화 배율 변경 2020-05-15 21:50:11 +09:00
Hide_D 4eebbb3e81 초토화에 전 장수 배신 1호 추가, 반환 금액 입력 2020-05-15 21:25:01 +09:00
Hide_D 8ddfc8fb4a 한계징병 2020-05-15 12:36:01 +09:00
Hide_D 14d2661be8 npc 조작 권한 안내 2020-05-15 00:38:26 +09:00
Hide_D ec71bf29b8 애니 집결 수정 2020-05-15 00:30:14 +09:00
1521 changed files with 142470 additions and 61246 deletions
+18
View File
@@ -0,0 +1,18 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"browsers": [
"last 2 versions"
]
},
"modules":false
}
]
],
"plugins": [
"lodash"
]
}
+22
View File
@@ -0,0 +1,22 @@
module.exports = {
root: true,
parser: "@typescript-eslint/parser",
parserOptions: {
"project": "./tsconfig.json"
},
ignorePatterns: ['*.test.ts', '.eslintrc.js', 'webpack.config.js', '*.js'],
overrides: [{
files: ['*.ts', '*.tsx'],
}],
plugins: [
"@typescript-eslint",
],
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
rules: {
'@typescript-eslint/no-floating-promises': 'error',
}
}
+54 -50
View File
@@ -1,50 +1,54 @@
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# 체섭 ignore
*.log
logs/*.txt
d_log/*.txt
d_log/*.zip
sess_*
*/logs/*.txt
*/logs/*/*.txt
*/logs/preserved
err.txt
che/.htaccess
kwe/.htaccess
pwe/.htaccess
twe/.htaccess
hwe/.htaccess
d_shared
d_pic/*.jpg
d_pic/*.gif
d_pic/*.png
d_pic/uploaded_image
d_setting/*.php
*/d_setting/*.php
*/d_setting/templates/*.php
**/old/*
test.php
/che
/kwe
/pwe
/nya
/pya
/twe
phpinfo.php
vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/*
*.sqlite3
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
/node_modules
package-lock.json
# 체섭 ignore
*.log
logs/*.txt
d_log/*.txt
d_log/*.zip
sess_*
*/logs/*.txt
*/logs/*/*.txt
*/logs/preserved
err.txt
che/.htaccess
kwe/.htaccess
pwe/.htaccess
twe/.htaccess
hwe/.htaccess
d_shared
d_pic/*.jpg
d_pic/*.gif
d_pic/*.png
d_pic/*.webp
d_pic/uploaded_image
d_setting/*.php
*/d_setting/*.php
*/d_setting/templates/*.php
*/data/file_cache
**/old/*
test.php
/che
/kwe
/pwe
/nya
/pya
/twe
phpinfo.php
vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/*
*.sqlite3
+2 -3
View File
@@ -23,7 +23,6 @@ return [
'f_config/config.php',
'hwe/a_bestGeneral.php',
'hwe/a_emperior.php',
'hwe/a_emperior2.php',
'hwe/a_emperior_detail.php',
'hwe/a_genList.php',
'hwe/a_hallOfFame.php',
@@ -51,10 +50,8 @@ return [
'hwe/b_tournament.php',
'hwe/b_troop.php',
'hwe/c_auction.php',
'hwe/c_die_immediately.php',
'hwe/c_dipcenter.php',
'hwe/c_tournament.php',
'hwe/c_vacation.php',
'hwe/c_vote.php',
'hwe/func.php',
'hwe/func_auction.php',
@@ -83,6 +80,7 @@ return [
'hwe/j_board_comment_add.php',
'hwe/j_board_get_articles.php',
'hwe/j_chief_turn.php',
'hwe/j_die_immediately.php',
'hwe/j_diplomacy_destroy_letter.php',
'hwe/j_diplomacy_get_letter.php',
'hwe/j_diplomacy_respond_letter.php',
@@ -115,6 +113,7 @@ return [
'hwe/j_set_general_command.php',
'hwe/j_simulate_battle.php',
'hwe/j_troop.php',
'hwe/j_vacation.php',
'hwe/lib.php',
'hwe/process_war.php',
'hwe/select_npc.php',
+23
View File
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>닫혀 있습니다.</title>
<script>
setTimeout(function(){
window.location = window.location+'/../';
}, 5000);
</script>
<style>
html, body{
background-color:black;
color:yellow;
}
</style>
</head>
<body>
서버가 닫혀있습니다.<br>
잠시 뒤에 입구로 이동합니다.
</body>
</html>
+5 -5
View File
@@ -9,18 +9,18 @@
* <code>mpm_event</code> 권장
* PHP 7.3 이상
* <code>php-fpm</code> 권장
* php에서 curl, pdo-sqlite을 실행가능해야 합니다. (기본값: 지원)
* mysqlnd가 지원되어야합니다. (기본값: 지원)
* mysqli
* php에서 curl, pdo-sqlite을 실행가능해야 합니다.
* mysqli, mysqlnd
* gd
* mbstring
* MariaDB 10.2.1 이상
* 현재 MySQL은 지원하지 않습니다.
* <code>git</code>
* <code>curl</code>
Linux는 Ubuntu 16.04, 18.04, Windows는 Windows 10에서 XAMPP를 사용한 환경에서 테스트되었습니다.
Linux는 Ubuntu 18.04, 20.04, Windows는 Windows 10에서 XAMPP, WSL2를 사용한 환경에서 테스트되었습니다.
Docker를 이용한 설치는 계획중입니다.
Docker를 이용한 설치는 테스트버전만 제공됩니다.
## Docker를 이용한 설치
+53 -51
View File
@@ -1,51 +1,53 @@
{
"name":"sammo-hid/sammo",
"description":"삼국지 모의전투 HiDCHe",
"license": [
"MIT",
"GPL-2.0-or-later",
"proprietary"
],
"config": {
"platform": {
"php": "7.3"
}
},
"require": {
"brandonwamboldt/utilphp": "^1.1",
"sergeytsalkov/meekrodb": "^2.3",
"league/plates": "^3.3",
"guzzlehttp/guzzle": "^6.3",
"scssphp/scssphp": "^1.0",
"monolog/monolog": "^1.23",
"firephp/firephp-core": "^0.4.0",
"vlucas/valitron": "^1.4",
"php-extended/php-tail": "^2.1",
"pguardiario/phpuri": "^1.0",
"symfony/lock": "^4.1",
"ezyang/htmlpurifier": "^4.10",
"xemlock/htmlpurifier-html5": "^0.1.7",
"catfan/medoo": "^1.5",
"phan/phan": "^2.7"
},
"autoload": {
"psr-4": {
"sammo\\": [
"src/sammo"
],
"kakao\\": [
"src/kakao"
]
},
"classmap": [
"d_setting/"
],
"exclude-from-classmap": [
"**/*.orig.php"
],
"files":[
"f_config/config.php"
]
}
}
{
"name":"sammo-hid/sammo",
"description":"삼국지 모의전투 HiDCHe",
"license": [
"MIT",
"GPL-2.0-or-later",
"proprietary"
],
"config": {
"platform": {
"php": "7.3"
}
},
"require": {
"brandonwamboldt/utilphp": "^1.1",
"sergeytsalkov/meekrodb": "^2.3",
"league/plates": "^3.3",
"guzzlehttp/guzzle": "^6.3",
"scssphp/scssphp": "^1.0",
"monolog/monolog": "^1.23",
"firephp/firephp-core": "^0.4.0",
"vlucas/valitron": "^1.4",
"php-extended/php-tail": "^2.1",
"pguardiario/phpuri": "^1.0",
"symfony/lock": "^4.1",
"ezyang/htmlpurifier": "^4.10",
"xemlock/htmlpurifier-html5": "^0.1.7",
"catfan/medoo": "^1.5",
"phan/phan": "*",
"erusev/parsedown-extra": "^0.8.1",
"nette/caching": "^3.0"
},
"autoload": {
"psr-4": {
"sammo\\": [
"src/sammo"
],
"kakao\\": [
"src/kakao"
]
},
"classmap": [
"d_setting/"
],
"exclude-from-classmap": [
"**/*.orig.php"
],
"files":[
"f_config/config.php"
]
}
}
Generated
+1382 -273
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": "7343763bee946f23e755edecd14d6b2c",
"content-hash": "2aeb036fc53a6fdc343bd2707d4697ee",
"packages": [
{
"name": "brandonwamboldt/utilphp",
@@ -50,20 +50,24 @@
"php",
"utility"
],
"support": {
"issues": "https://github.com/brandonwamboldt/utilphp/issues",
"source": "https://github.com/brandonwamboldt/utilphp/tree/master"
},
"time": "2015-02-02T17:56:14+00:00"
},
{
"name": "catfan/medoo",
"version": "v1.7.8",
"version": "v1.7.10",
"source": {
"type": "git",
"url": "https://github.com/catfan/Medoo.git",
"reference": "dd9d570584cfb1e09ec470608479b86e41d5b60d"
"reference": "2d675f73e23f63bbaeb9a8aa33318659a3d3c32f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/catfan/Medoo/zipball/dd9d570584cfb1e09ec470608479b86e41d5b60d",
"reference": "dd9d570584cfb1e09ec470608479b86e41d5b60d",
"url": "https://api.github.com/repos/catfan/Medoo/zipball/2d675f73e23f63bbaeb9a8aa33318659a3d3c32f",
"reference": "2d675f73e23f63bbaeb9a8aa33318659a3d3c32f",
"shasum": ""
},
"require": {
@@ -110,32 +114,37 @@
"sql",
"sqlite"
],
"time": "2019-12-19T05:04:34+00:00"
"support": {
"issues": "https://github.com/catfan/Medoo/issues",
"source": "https://github.com/catfan/Medoo"
},
"time": "2020-02-11T08:20:42+00:00"
},
{
"name": "composer/semver",
"version": "1.5.1",
"version": "3.2.5",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de"
"reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de",
"reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de",
"url": "https://api.github.com/repos/composer/semver/zipball/31f3ea725711245195f62e54ffa402d8ef2fdba9",
"reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0"
"php": "^5.3.2 || ^7.0 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^4.5 || ^5.0.5"
"phpstan/phpstan": "^0.12.54",
"symfony/phpunit-bridge": "^4.2 || ^5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
"dev-main": "3.x-dev"
}
},
"autoload": {
@@ -171,28 +180,48 @@
"validation",
"versioning"
],
"time": "2020-01-13T12:06:48+00:00"
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.2.5"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
],
"time": "2021-05-24T12:41:47+00:00"
},
{
"name": "composer/xdebug-handler",
"version": "1.4.1",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/composer/xdebug-handler.git",
"reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7"
"reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/1ab9842d69e64fb3a01be6b656501032d1b78cb7",
"reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/84674dd3a7575ba617f5a76d7e9e29a7d3891339",
"reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0",
"psr/log": "^1.0"
"psr/log": "^1 || ^2 || ^3"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8"
"phpstan/phpstan": "^0.12.55",
"symfony/phpunit-bridge": "^4.2 || ^5"
},
"type": "library",
"autoload": {
@@ -215,26 +244,140 @@
"Xdebug",
"performance"
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/xdebug-handler/issues",
"source": "https://github.com/composer/xdebug-handler/tree/2.0.2"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
],
"time": "2020-03-01T12:26:26+00:00"
"time": "2021-07-31T17:03:58+00:00"
},
{
"name": "ezyang/htmlpurifier",
"version": "v4.12.0",
"name": "erusev/parsedown",
"version": "1.7.4",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "a617e55bc62a87eec73bd456d146d134ad716f03"
"url": "https://github.com/erusev/parsedown.git",
"reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/a617e55bc62a87eec73bd456d146d134ad716f03",
"reference": "a617e55bc62a87eec73bd456d146d134ad716f03",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
},
"type": "library",
"autoload": {
"psr-0": {
"Parsedown": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"description": "Parser for Markdown.",
"homepage": "http://parsedown.org",
"keywords": [
"markdown",
"parser"
],
"support": {
"issues": "https://github.com/erusev/parsedown/issues",
"source": "https://github.com/erusev/parsedown/tree/1.7.x"
},
"time": "2019-12-30T22:54:17+00:00"
},
{
"name": "erusev/parsedown-extra",
"version": "0.8.1",
"source": {
"type": "git",
"url": "https://github.com/erusev/parsedown-extra.git",
"reference": "91ac3ff98f0cea243bdccc688df43810f044dcef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown-extra/zipball/91ac3ff98f0cea243bdccc688df43810f044dcef",
"reference": "91ac3ff98f0cea243bdccc688df43810f044dcef",
"shasum": ""
},
"require": {
"erusev/parsedown": "^1.7.4"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
},
"type": "library",
"autoload": {
"psr-0": {
"ParsedownExtra": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"description": "An extension of Parsedown that adds support for Markdown Extra.",
"homepage": "https://github.com/erusev/parsedown-extra",
"keywords": [
"markdown",
"markdown extra",
"parsedown",
"parser"
],
"support": {
"issues": "https://github.com/erusev/parsedown-extra/issues",
"source": "https://github.com/erusev/parsedown-extra/tree/0.8.x"
},
"time": "2019-12-30T23:20:37+00:00"
},
{
"name": "ezyang/htmlpurifier",
"version": "v4.13.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/08e27c97e4c6ed02f37c5b2b20488046c8d90d75",
"reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75",
"shasum": ""
},
"require": {
@@ -250,6 +393,9 @@
},
"files": [
"library/HTMLPurifier.composer.php"
],
"exclude-from-classmap": [
"/library/HTMLPurifier/Language/"
]
},
"notification-url": "https://packagist.org/downloads/",
@@ -268,29 +414,33 @@
"keywords": [
"html"
],
"time": "2019-10-28T03:44:26+00:00"
"support": {
"issues": "https://github.com/ezyang/htmlpurifier/issues",
"source": "https://github.com/ezyang/htmlpurifier/tree/master"
},
"time": "2020-06-29T00:56:53+00:00"
},
{
"name": "felixfbecker/advanced-json-rpc",
"version": "v3.1.1",
"version": "v3.2.1",
"source": {
"type": "git",
"url": "https://github.com/felixfbecker/php-advanced-json-rpc.git",
"reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40"
"reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/0ed363f8de17d284d479ec813c9ad3f6834b5c40",
"reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40",
"url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/b5f37dbff9a8ad360ca341f3240dc1c168b45447",
"reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447",
"shasum": ""
},
"require": {
"netresearch/jsonmapper": "^1.0 || ^2.0",
"php": ">=7.0",
"phpdocumentor/reflection-docblock": "^4.0.0 || ^5.0.0"
"netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
"php": "^7.1 || ^8.0",
"phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0.0"
"phpunit/phpunit": "^7.0 || ^8.0"
},
"type": "library",
"autoload": {
@@ -309,7 +459,11 @@
}
],
"description": "A more advanced JSONRPC implementation",
"time": "2020-03-11T15:21:41+00:00"
"support": {
"issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues",
"source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.1"
},
"time": "2021-06-11T22:34:44+00:00"
},
{
"name": "firephp/firephp-core",
@@ -345,27 +499,33 @@
],
"description": "Traditional FirePHPCore library for sending PHP variables to the browser.",
"homepage": "https://github.com/firephp/firephp-core",
"support": {
"forum": "http://groups.google.com/group/firephp-dev",
"issues": "https://github.com/firephp/firephp-core/issues",
"source": "https://github.com/firephp/firephp-core"
},
"time": "2013-04-23T15:28:20+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "6.5.2",
"version": "6.5.5",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "43ece0e75098b7ecd8d13918293029e555a50f82"
"reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82",
"reference": "43ece0e75098b7ecd8d13918293029e555a50f82",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e",
"reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.6.1",
"php": ">=5.5"
"php": ">=5.5",
"symfony/polyfill-intl-idn": "^1.17.0"
},
"require-dev": {
"ext-curl": "*",
@@ -373,7 +533,6 @@
"psr/log": "^1.1"
},
"suggest": {
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
"psr/log": "Required for using the Log middleware"
},
"type": "library",
@@ -412,27 +571,31 @@
"rest",
"web service"
],
"time": "2019-12-23T11:57:10+00:00"
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/6.5"
},
"time": "2020-06-16T21:01:06+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "v1.3.1",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
"reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d",
"reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d",
"shasum": ""
},
"require": {
"php": ">=5.5.0"
"php": ">=5.5"
},
"require-dev": {
"phpunit/phpunit": "^4.0"
"symfony/phpunit-bridge": "^4.4 || ^5.1"
},
"type": "library",
"extra": {
@@ -463,20 +626,24 @@
"keywords": [
"promise"
],
"time": "2016-12-20T10:07:11+00:00"
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/1.4.1"
},
"time": "2021-03-07T09:25:29+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "1.6.1",
"version": "1.8.2",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "239400de7a173fe9901b9ac7c06497751f00727a"
"reference": "dc960a912984efb74d0a90222870c72c87f10c91"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a",
"reference": "239400de7a173fe9901b9ac7c06497751f00727a",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91",
"reference": "dc960a912984efb74d0a90222870c72c87f10c91",
"shasum": ""
},
"require": {
@@ -489,15 +656,15 @@
},
"require-dev": {
"ext-zlib": "*",
"phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8"
"phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10"
},
"suggest": {
"zendframework/zend-httphandlerrunner": "Emit PSR-7 responses"
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6-dev"
"dev-master": "1.7-dev"
}
},
"autoload": {
@@ -534,29 +701,33 @@
"uri",
"url"
],
"time": "2019-07-01T23:21:34+00:00"
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/1.8.2"
},
"time": "2021-04-26T09:17:50+00:00"
},
{
"name": "league/plates",
"version": "3.3.0",
"version": "v3.4.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/plates.git",
"reference": "b1684b6f127714497a0ef927ce42c0b44b45a8af"
"reference": "6d3ee31199b536a4e003b34a356ca20f6f75496a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/plates/zipball/b1684b6f127714497a0ef927ce42c0b44b45a8af",
"reference": "b1684b6f127714497a0ef927ce42c0b44b45a8af",
"url": "https://api.github.com/repos/thephpleague/plates/zipball/6d3ee31199b536a4e003b34a356ca20f6f75496a",
"reference": "6d3ee31199b536a4e003b34a356ca20f6f75496a",
"shasum": ""
},
"require": {
"php": "^5.3 | ^7.0"
"php": "^7.0|^8.0"
},
"require-dev": {
"mikey179/vfsstream": "^1.4",
"phpunit/phpunit": "~4.0",
"squizlabs/php_codesniffer": "~1.5"
"mikey179/vfsstream": "^1.6",
"phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
@@ -578,10 +749,15 @@
"name": "Jonathan Reinink",
"email": "jonathan@reinink.ca",
"role": "Developer"
},
{
"name": "RJ Garcia",
"email": "ragboyjr@icloud.com",
"role": "Developer"
}
],
"description": "Plates, the native PHP template system that's fast, easy to use and easy to extend.",
"homepage": "http://platesphp.com",
"homepage": "https://platesphp.com",
"keywords": [
"league",
"package",
@@ -589,27 +765,31 @@
"templating",
"views"
],
"time": "2016-12-28T00:14:17+00:00"
"support": {
"issues": "https://github.com/thephpleague/plates/issues",
"source": "https://github.com/thephpleague/plates/tree/v3.4.0"
},
"time": "2020-12-25T05:00:37+00:00"
},
{
"name": "microsoft/tolerant-php-parser",
"version": "v0.0.20",
"version": "v0.1.1",
"source": {
"type": "git",
"url": "https://github.com/microsoft/tolerant-php-parser.git",
"reference": "c5e2bf5d8c9f4f27eef1370bd39ea2d1f374eeb4"
"reference": "6a965617cf484355048ac6d2d3de7b6ec93abb16"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/microsoft/tolerant-php-parser/zipball/c5e2bf5d8c9f4f27eef1370bd39ea2d1f374eeb4",
"reference": "c5e2bf5d8c9f4f27eef1370bd39ea2d1f374eeb4",
"url": "https://api.github.com/repos/microsoft/tolerant-php-parser/zipball/6a965617cf484355048ac6d2d3de7b6ec93abb16",
"reference": "6a965617cf484355048ac6d2d3de7b6ec93abb16",
"shasum": ""
},
"require": {
"php": ">=7.0"
"php": ">=7.2"
},
"require-dev": {
"phpunit/phpunit": "^6.4"
"phpunit/phpunit": "^8.5.15"
},
"type": "library",
"autoload": {
@@ -630,20 +810,24 @@
}
],
"description": "Tolerant PHP-to-AST parser designed for IDE usage scenarios",
"time": "2020-02-18T02:57:19+00:00"
"support": {
"issues": "https://github.com/microsoft/tolerant-php-parser/issues",
"source": "https://github.com/microsoft/tolerant-php-parser/tree/v0.1.1"
},
"time": "2021-07-16T21:28:12+00:00"
},
{
"name": "monolog/monolog",
"version": "1.25.3",
"version": "1.26.1",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "fa82921994db851a8becaf3787a9e73c5976b6f1"
"reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/fa82921994db851a8becaf3787a9e73c5976b6f1",
"reference": "fa82921994db851a8becaf3787a9e73c5976b6f1",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/c6b00f05152ae2c9b04a448f99c7590beb6042f5",
"reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5",
"shasum": ""
},
"require": {
@@ -657,11 +841,10 @@
"aws/aws-sdk-php": "^2.4.9 || ^3.0",
"doctrine/couchdb": "~1.0@dev",
"graylog2/gelf-php": "~1.0",
"jakub-onderka/php-parallel-lint": "0.9",
"php-amqplib/php-amqplib": "~2.4",
"php-console/php-console": "^3.1.3",
"phpstan/phpstan": "^0.12.59",
"phpunit/phpunit": "~4.5",
"phpunit/phpunit-mock-objects": "2.3.0",
"ruflin/elastica": ">=0.90 <3.0",
"sentry/sentry": "^0.13",
"swiftmailer/swiftmailer": "^5.3|^6.0"
@@ -680,11 +863,6 @@
"sentry/sentry": "Allow sending log messages to a Sentry server"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Monolog\\": "src/Monolog"
@@ -708,20 +886,34 @@
"logging",
"psr-3"
],
"time": "2019-12-20T14:15:16+00:00"
"support": {
"issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/1.26.1"
},
"funding": [
{
"url": "https://github.com/Seldaek",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
"type": "tidelift"
}
],
"time": "2021-05-28T08:32:12+00:00"
},
{
"name": "netresearch/jsonmapper",
"version": "v2.1.0",
"version": "v4.0.0",
"source": {
"type": "git",
"url": "https://github.com/cweiske/jsonmapper.git",
"reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e"
"reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/e0f1e33a71587aca81be5cffbb9746510e1fe04e",
"reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e",
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d",
"reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d",
"shasum": ""
},
"require": {
@@ -729,10 +921,10 @@
"ext-pcre": "*",
"ext-reflection": "*",
"ext-spl": "*",
"php": ">=5.6"
"php": ">=7.1"
},
"require-dev": {
"phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4 || ~7.0",
"phpunit/phpunit": "~7.5 || ~8.0 || ~9.0",
"squizlabs/php_codesniffer": "~3.5"
},
"type": "library",
@@ -754,7 +946,235 @@
}
],
"description": "Map nested JSON structures onto PHP classes",
"time": "2020-04-16T18:48:43+00:00"
"support": {
"email": "cweiske@cweiske.de",
"issues": "https://github.com/cweiske/jsonmapper/issues",
"source": "https://github.com/cweiske/jsonmapper/tree/v4.0.0"
},
"time": "2020-12-01T19:48:11+00:00"
},
{
"name": "nette/caching",
"version": "v3.1.1",
"source": {
"type": "git",
"url": "https://github.com/nette/caching.git",
"reference": "3e771c589dee414724be473c24ad16dae50c1960"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/caching/zipball/3e771c589dee414724be473c24ad16dae50c1960",
"reference": "3e771c589dee414724be473c24ad16dae50c1960",
"shasum": ""
},
"require": {
"nette/finder": "^2.4 || ^3.0",
"nette/utils": "^2.4 || ^3.0",
"php": ">=7.2 <8.1"
},
"require-dev": {
"latte/latte": "^2.10",
"nette/di": "^v3.0",
"nette/tester": "^2.0",
"phpstan/phpstan": "^0.12",
"tracy/tracy": "^2.4"
},
"suggest": {
"ext-pdo_sqlite": "to use SQLiteStorage or SQLiteJournal"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause",
"GPL-2.0-only",
"GPL-3.0-only"
],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https://nette.org/contributors"
}
],
"description": "⏱ Nette Caching: library with easy-to-use API and many cache backends.",
"homepage": "https://nette.org",
"keywords": [
"cache",
"journal",
"memcached",
"nette",
"sqlite"
],
"support": {
"issues": "https://github.com/nette/caching/issues",
"source": "https://github.com/nette/caching/tree/v3.1.1"
},
"time": "2021-03-06T14:07:38+00:00"
},
{
"name": "nette/finder",
"version": "v2.5.2",
"source": {
"type": "git",
"url": "https://github.com/nette/finder.git",
"reference": "4ad2c298eb8c687dd0e74ae84206a4186eeaed50"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/finder/zipball/4ad2c298eb8c687dd0e74ae84206a4186eeaed50",
"reference": "4ad2c298eb8c687dd0e74ae84206a4186eeaed50",
"shasum": ""
},
"require": {
"nette/utils": "^2.4 || ^3.0",
"php": ">=7.1"
},
"conflict": {
"nette/nette": "<2.2"
},
"require-dev": {
"nette/tester": "^2.0",
"phpstan/phpstan": "^0.12",
"tracy/tracy": "^2.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.5-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause",
"GPL-2.0",
"GPL-3.0"
],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https://nette.org/contributors"
}
],
"description": "🔍 Nette Finder: find files and directories with an intuitive API.",
"homepage": "https://nette.org",
"keywords": [
"filesystem",
"glob",
"iterator",
"nette"
],
"support": {
"issues": "https://github.com/nette/finder/issues",
"source": "https://github.com/nette/finder/tree/v2.5.2"
},
"time": "2020-01-03T20:35:40+00:00"
},
{
"name": "nette/utils",
"version": "v3.2.2",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
"reference": "967cfc4f9a1acd5f1058d76715a424c53343c20c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/967cfc4f9a1acd5f1058d76715a424c53343c20c",
"reference": "967cfc4f9a1acd5f1058d76715a424c53343c20c",
"shasum": ""
},
"require": {
"php": ">=7.2 <8.1"
},
"conflict": {
"nette/di": "<3.0.6"
},
"require-dev": {
"nette/tester": "~2.0",
"phpstan/phpstan": "^0.12",
"tracy/tracy": "^2.3"
},
"suggest": {
"ext-gd": "to use Image",
"ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()",
"ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
"ext-json": "to use Nette\\Utils\\Json",
"ext-mbstring": "to use Strings::lower() etc...",
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()",
"ext-xml": "to use Strings::length() etc. when mbstring is not available"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause",
"GPL-2.0-only",
"GPL-3.0-only"
],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https://nette.org/contributors"
}
],
"description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.",
"homepage": "https://nette.org",
"keywords": [
"array",
"core",
"datetime",
"images",
"json",
"nette",
"paginator",
"password",
"slugify",
"string",
"unicode",
"utf-8",
"utility",
"validation"
],
"support": {
"issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v3.2.2"
},
"time": "2021-03-03T22:53:25+00:00"
},
{
"name": "pguardiario/phpuri",
@@ -778,47 +1198,52 @@
},
"notification-url": "https://packagist.org/downloads/",
"description": "A php library for converting relative urls to absolute.",
"support": {
"issues": "https://github.com/monkeysuffrage/phpuri/issues",
"source": "https://github.com/monkeysuffrage/phpuri/tree/1.0.0"
},
"time": "2015-05-24T09:13:17+00:00"
},
{
"name": "phan/phan",
"version": "2.7.1",
"version": "5.0.0",
"source": {
"type": "git",
"url": "https://github.com/phan/phan.git",
"reference": "67c51bb1593e5c30271fc16d691b82e318b90b77"
"reference": "f36b6b9a2f4143a25f35ce94d712ceb0527e9d90"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phan/phan/zipball/67c51bb1593e5c30271fc16d691b82e318b90b77",
"reference": "67c51bb1593e5c30271fc16d691b82e318b90b77",
"url": "https://api.github.com/repos/phan/phan/zipball/f36b6b9a2f4143a25f35ce94d712ceb0527e9d90",
"reference": "f36b6b9a2f4143a25f35ce94d712ceb0527e9d90",
"shasum": ""
},
"require": {
"composer/semver": "^1.4",
"composer/xdebug-handler": "^1.3.2",
"composer/semver": "^1.4|^2.0|^3.0",
"composer/xdebug-handler": "^1.3.2|^2.0.0",
"ext-filter": "*",
"ext-json": "*",
"ext-tokenizer": "*",
"felixfbecker/advanced-json-rpc": "^3.0.4",
"microsoft/tolerant-php-parser": "0.0.20",
"netresearch/jsonmapper": "^1.6.0|^2.0",
"php": "^7.1.0",
"sabre/event": "^5.0",
"symfony/console": "^2.3|^3.0|^4.0|^5.0",
"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",
"symfony/polyfill-mbstring": "^1.11.0",
"symfony/polyfill-php72": "^1.15"
"symfony/polyfill-php80": "^1.20.0",
"tysonandre/var_representation_polyfill": "^0.0.2"
},
"require-dev": {
"brianium/paratest": "^4.0.0",
"phpunit/phpunit": "^7.5.0"
"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.6+ is recommended.",
"ext-ast": "Needed for parsing ASTs (unless --use-fallback-parser is used). 1.0.1+ is needed, 1.0.14+ 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",
"ext-tokenizer": "Needed for fallback/polyfill parser support and file/line-based suppressions."
"ext-tokenizer": "Needed for fallback/polyfill parser support and file/line-based suppressions.",
"ext-var_representation": "Suggested for converting values to strings in issue messages"
},
"bin": [
"phan",
@@ -852,7 +1277,11 @@
"php",
"static"
],
"time": "2020-04-12T01:25:29+00:00"
"support": {
"issues": "https://github.com/phan/phan/issues",
"source": "https://github.com/phan/phan/tree/5.0.0"
},
"time": "2021-08-01T18:17:28+00:00"
},
{
"name": "php-extended/php-system",
@@ -892,6 +1321,10 @@
"php",
"system"
],
"support": {
"issues": "https://gitlab.com/php-extended/php-system/issues",
"source": "https://gitlab.com/php-extended/php-system"
},
"time": "2018-06-07T06:03:27+00:00"
},
{
@@ -936,29 +1369,33 @@
"php",
"tail"
],
"support": {
"issues": "https://gitlab.com/php-extended/php-tail/issues",
"source": "https://gitlab.com/php-extended/php-tail"
},
"time": "2018-06-07T06:04:58+00:00"
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.1.0",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
"reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b"
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/6568f4687e5b41b054365f9ae03fcb1ed5f2069b",
"reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
"shasum": ""
},
"require": {
"php": ">=7.1"
"php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
"dev-2.x": "2.x-dev"
}
},
"autoload": {
@@ -985,32 +1422,35 @@
"reflection",
"static analysis"
],
"time": "2020-04-27T09:25:28+00:00"
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
"source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
},
"time": "2020-06-27T09:03:43+00:00"
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "5.1.0",
"version": "5.2.2",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e"
"reference": "069a785b2141f5bcf49f3e353548dc1cce6df556"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e",
"reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556",
"reference": "069a785b2141f5bcf49f3e353548dc1cce6df556",
"shasum": ""
},
"require": {
"ext-filter": "^7.1",
"php": "^7.2",
"phpdocumentor/reflection-common": "^2.0",
"phpdocumentor/type-resolver": "^1.0",
"webmozart/assert": "^1"
"ext-filter": "*",
"php": "^7.2 || ^8.0",
"phpdocumentor/reflection-common": "^2.2",
"phpdocumentor/type-resolver": "^1.3",
"webmozart/assert": "^1.9.1"
},
"require-dev": {
"doctrine/instantiator": "^1",
"mockery/mockery": "^1"
"mockery/mockery": "~1.3.2"
},
"type": "library",
"extra": {
@@ -1038,34 +1478,37 @@
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"time": "2020-02-22T12:28:44+00:00"
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master"
},
"time": "2020-09-03T19:13:55+00:00"
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.1.0",
"version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "7462d5f123dfc080dfdf26897032a6513644fc95"
"reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/7462d5f123dfc080dfdf26897032a6513644fc95",
"reference": "7462d5f123dfc080dfdf26897032a6513644fc95",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0",
"reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0",
"shasum": ""
},
"require": {
"php": "^7.2",
"php": "^7.2 || ^8.0",
"phpdocumentor/reflection-common": "^2.0"
},
"require-dev": {
"ext-tokenizer": "^7.2",
"mockery/mockery": "~1"
"ext-tokenizer": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
"dev-1.x": "1.x-dev"
}
},
"autoload": {
@@ -1084,31 +1527,30 @@
}
],
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"time": "2020-02-18T18:59:58+00:00"
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0"
},
"time": "2020-09-17T18:55:26+00:00"
},
{
"name": "psr/container",
"version": "1.0.0",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
"reference": "8622567409010282b7aeebe4bb841fe98b58dcaf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf",
"reference": "8622567409010282b7aeebe4bb841fe98b58dcaf",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
"php": ">=7.2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
@@ -1121,7 +1563,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common Container Interface (PHP FIG PSR-11)",
@@ -1133,7 +1575,11 @@
"container-interop",
"psr"
],
"time": "2017-02-14T16:28:37+00:00"
"support": {
"issues": "https://github.com/php-fig/container/issues",
"source": "https://github.com/php-fig/container/tree/1.1.1"
},
"time": "2021-03-05T17:36:06+00:00"
},
{
"name": "psr/http-message",
@@ -1183,20 +1629,23 @@
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/master"
},
"time": "2016-08-06T14:39:51+00:00"
},
{
"name": "psr/log",
"version": "1.1.2",
"version": "1.1.4",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": ""
},
"require": {
@@ -1220,7 +1669,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
@@ -1230,7 +1679,10 @@
"psr",
"psr-3"
],
"time": "2019-11-01T11:05:21+00:00"
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"time": "2021-05-03T11:20:27+00:00"
},
{
"name": "ralouphie/getallheaders",
@@ -1270,28 +1722,33 @@
}
],
"description": "A polyfill for getallheaders.",
"support": {
"issues": "https://github.com/ralouphie/getallheaders/issues",
"source": "https://github.com/ralouphie/getallheaders/tree/develop"
},
"time": "2019-03-08T08:55:37+00:00"
},
{
"name": "sabre/event",
"version": "5.1.0",
"version": "5.1.2",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/event.git",
"reference": "d00a17507af0e7544cfe17096372f5d733e3b276"
"reference": "c120bec57c17b6251a496efc82b732418b49d50a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/event/zipball/d00a17507af0e7544cfe17096372f5d733e3b276",
"reference": "d00a17507af0e7544cfe17096372f5d733e3b276",
"url": "https://api.github.com/repos/sabre-io/event/zipball/c120bec57c17b6251a496efc82b732418b49d50a",
"reference": "c120bec57c17b6251a496efc82b732418b49d50a",
"shasum": ""
},
"require": {
"php": "^7.1"
"php": "^7.1 || ^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.16.1",
"phpunit/phpunit": "^7 || ^8"
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
},
"type": "library",
"autoload": {
@@ -1330,20 +1787,25 @@
"reactor",
"signal"
],
"time": "2020-01-31T18:52:29+00:00"
"support": {
"forum": "https://groups.google.com/group/sabredav-discuss",
"issues": "https://github.com/sabre-io/event/issues",
"source": "https://github.com/fruux/sabre-event"
},
"time": "2020-10-03T11:02:22+00:00"
},
{
"name": "scssphp/scssphp",
"version": "1.0.6",
"version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/scssphp/scssphp.git",
"reference": "5b3c9d704950d8f9637f5110c36c281ec47dc13c"
"reference": "b83594e2323c5d6e80785df3f91b9d1d32aad530"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/5b3c9d704950d8f9637f5110c36c281ec47dc13c",
"reference": "5b3c9d704950d8f9637f5110c36c281ec47dc13c",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/b83594e2323c5d6e80785df3f91b9d1d32aad530",
"reference": "b83594e2323c5d6e80785df3f91b9d1d32aad530",
"shasum": ""
},
"require": {
@@ -1352,11 +1814,19 @@
"php": ">=5.6.0"
},
"require-dev": {
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3",
"squizlabs/php_codesniffer": "~2.5",
"twbs/bootstrap": "~4.3",
"bamarni/composer-bin-plugin": "^1.4",
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4",
"sass/sass-spec": "*",
"squizlabs/php_codesniffer": "~3.5",
"symfony/phpunit-bridge": "^5.1",
"twbs/bootstrap": "~5.0",
"twbs/bootstrap4": "4.6.0",
"zurb/foundation": "~6.5"
},
"suggest": {
"ext-iconv": "Can be used as fallback when ext-mbstring is not available",
"ext-mbstring": "For best performance, mbstring should be installed as it is faster than ext-iconv"
},
"bin": [
"bin/pscss"
],
@@ -1391,24 +1861,28 @@
"scss",
"stylesheet"
],
"time": "2019-12-12T05:00:52+00:00"
"support": {
"issues": "https://github.com/scssphp/scssphp/issues",
"source": "https://github.com/scssphp/scssphp/tree/v1.6.0"
},
"time": "2021-07-02T16:28:10+00:00"
},
{
"name": "sergeytsalkov/meekrodb",
"version": "v2.3",
"version": "v2.4",
"source": {
"type": "git",
"url": "https://github.com/SergeyTsalkov/meekrodb.git",
"reference": "eb36858f1aff94ae1665900e681a1cfb78563ee1"
"reference": "e30c240d54bc81f58c58507a9ed768032eb494a5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/SergeyTsalkov/meekrodb/zipball/eb36858f1aff94ae1665900e681a1cfb78563ee1",
"reference": "eb36858f1aff94ae1665900e681a1cfb78563ee1",
"url": "https://api.github.com/repos/SergeyTsalkov/meekrodb/zipball/e30c240d54bc81f58c58507a9ed768032eb494a5",
"reference": "e30c240d54bc81f58c58507a9ed768032eb494a5",
"shasum": ""
},
"require": {
"php": ">=5.2.0"
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
@@ -1434,39 +1908,49 @@
"mysqli",
"pdo"
],
"time": "2014-06-16T22:40:22+00:00"
"support": {
"email": "support@meekro.com",
"issues": "https://github.com/SergeyTsalkov/meekrodb/issues",
"source": "https://github.com/SergeyTsalkov/meekrodb/tree/v2.4"
},
"time": "2021-06-29T04:31:23+00:00"
},
{
"name": "symfony/console",
"version": "v5.0.8",
"version": "v5.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "5fa1caadc8cdaa17bcfb25219f3b53fe294a9935"
"reference": "51b71afd6d2dc8f5063199357b9880cea8d8bfe2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/5fa1caadc8cdaa17bcfb25219f3b53fe294a9935",
"reference": "5fa1caadc8cdaa17bcfb25219f3b53fe294a9935",
"url": "https://api.github.com/repos/symfony/console/zipball/51b71afd6d2dc8f5063199357b9880cea8d8bfe2",
"reference": "51b71afd6d2dc8f5063199357b9880cea8d8bfe2",
"shasum": ""
},
"require": {
"php": "^7.2.5",
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1",
"symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php73": "^1.8",
"symfony/service-contracts": "^1.1|^2"
"symfony/polyfill-php80": "^1.16",
"symfony/service-contracts": "^1.1|^2",
"symfony/string": "^5.1"
},
"conflict": {
"psr/log": ">=3",
"symfony/dependency-injection": "<4.4",
"symfony/dotenv": "<5.1",
"symfony/event-dispatcher": "<4.4",
"symfony/lock": "<4.4",
"symfony/process": "<4.4"
},
"provide": {
"psr/log-implementation": "1.0"
"psr/log-implementation": "1.0|2.0"
},
"require-dev": {
"psr/log": "~1.0",
"psr/log": "^1|^2",
"symfony/config": "^4.4|^5.0",
"symfony/dependency-injection": "^4.4|^5.0",
"symfony/event-dispatcher": "^4.4|^5.0",
@@ -1481,11 +1965,6 @@
"symfony/process": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
@@ -1508,8 +1987,17 @@
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Console Component",
"description": "Eases the creation of beautiful and testable command line interfaces",
"homepage": "https://symfony.com",
"keywords": [
"cli",
"command line",
"console",
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v5.3.6"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -1524,40 +2012,102 @@
"type": "tidelift"
}
],
"time": "2020-03-30T11:42:42+00:00"
"time": "2021-07-27T19:10:22+00:00"
},
{
"name": "symfony/lock",
"version": "v4.4.3",
"name": "symfony/deprecation-contracts",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/lock.git",
"reference": "6c4f5b620871cfef5b004fc57f2ca74572ae03b3"
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/lock/zipball/6c4f5b620871cfef5b004fc57f2ca74572ae03b3",
"reference": "6c4f5b620871cfef5b004fc57f2ca74572ae03b3",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627",
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"psr/log": "~1.0"
},
"conflict": {
"doctrine/dbal": "<2.5"
},
"require-dev": {
"doctrine/dbal": "~2.5",
"mongodb/mongodb": "~1.1",
"predis/predis": "~1.0"
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.4-dev"
"dev-main": "2.4-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
"files": [
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-03-23T23:28:01+00:00"
},
{
"name": "symfony/lock",
"version": "v4.4.27",
"source": {
"type": "git",
"url": "https://github.com/symfony/lock.git",
"reference": "6ca476d4ac992802f2a4043929f68f1818449486"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/lock/zipball/6ca476d4ac992802f2a4043929f68f1818449486",
"reference": "6ca476d4ac992802f2a4043929f68f1818449486",
"shasum": ""
},
"require": {
"php": ">=7.1.3",
"psr/log": "^1|^2|^3",
"symfony/polyfill-php80": "^1.16"
},
"conflict": {
"doctrine/dbal": "<2.6"
},
"require-dev": {
"doctrine/dbal": "^2.6|^3.0",
"predis/predis": "~1.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Lock\\": ""
@@ -1580,7 +2130,7 @@
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Lock Component",
"description": "Creates and manages locks, a mechanism to provide exclusive access to a shared resource",
"homepage": "https://symfony.com",
"keywords": [
"cas",
@@ -1590,24 +2140,41 @@
"redlock",
"semaphore"
],
"time": "2020-01-04T13:00:46+00:00"
"support": {
"source": "https://github.com/symfony/lock/tree/v4.4.27"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-07-23T15:41:52+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.15.0",
"version": "v1.23.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14"
"reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/4719fa9c18b0464d399f1a63bf624b42b6fa8d14",
"reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce",
"reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
"php": ">=7.1"
},
"suggest": {
"ext-ctype": "For best performance"
@@ -1615,7 +2182,11 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
@@ -1648,6 +2219,9 @@
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -1662,24 +2236,276 @@
"type": "tidelift"
}
],
"time": "2020-02-27T09:26:54+00:00"
"time": "2021-02-19T12:13:01+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.15.0",
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.23.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac"
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "16880ba9c5ebe3642d1995ab866db29270b36535"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/16880ba9c5ebe3642d1995ab866db29270b36535",
"reference": "16880ba9c5ebe3642d1995ab866db29270b36535",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
"php": ">=7.1"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Intl\\Grapheme\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for intl's grapheme_* functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"grapheme",
"intl",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-05-27T12:26:48+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.23.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "65bd267525e82759e7d8c4e8ceea44f398838e65"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65",
"reference": "65bd267525e82759e7d8c4e8ceea44f398838e65",
"shasum": ""
},
"require": {
"php": ">=7.1",
"symfony/polyfill-intl-normalizer": "^1.10",
"symfony/polyfill-php72": "^1.10"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Intl\\Idn\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Laurent Bassin",
"email": "laurent@bassin.info"
},
{
"name": "Trevor Rowbotham",
"email": "trevor.rowbotham@pm.me"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"idn",
"intl",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.23.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-05-27T09:27:20+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.23.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8",
"reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
},
"files": [
"bootstrap.php"
],
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for intl's Normalizer class and related functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"intl",
"normalizer",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-02-19T12:13:01+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.23.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6",
"reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"suggest": {
"ext-mbstring": "For best performance"
@@ -1687,7 +2513,11 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
@@ -1721,6 +2551,9 @@
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -1735,29 +2568,33 @@
"type": "tidelift"
}
],
"time": "2020-03-09T19:04:49+00:00"
"time": "2021-05-27T12:26:48+00:00"
},
{
"name": "symfony/polyfill-php72",
"version": "v1.15.0",
"version": "v1.23.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "37b0976c78b94856543260ce09b460a7bc852747"
"reference": "9a142215a36a3888e30d0a9eeea9766764e96976"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/37b0976c78b94856543260ce09b460a7bc852747",
"reference": "37b0976c78b94856543260ce09b460a7bc852747",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976",
"reference": "9a142215a36a3888e30d0a9eeea9766764e96976",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
@@ -1790,6 +2627,9 @@
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -1804,29 +2644,33 @@
"type": "tidelift"
}
],
"time": "2020-02-27T09:26:54+00:00"
"time": "2021-05-27T09:17:38+00:00"
},
{
"name": "symfony/polyfill-php73",
"version": "v1.15.0",
"version": "v1.23.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
"reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7"
"reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7",
"reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010",
"reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
@@ -1862,6 +2706,9 @@
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -1876,25 +2723,108 @@
"type": "tidelift"
}
],
"time": "2020-02-27T09:26:54+00:00"
"time": "2021-02-19T12:13:01+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v2.0.1",
"name": "symfony/polyfill-php80",
"version": "v1.23.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "144c5e51266b281231e947b51223ba14acf1a749"
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749",
"reference": "144c5e51266b281231e947b51223ba14acf1a749",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be",
"reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be",
"shasum": ""
},
"require": {
"php": "^7.2.5",
"psr/container": "^1.0"
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"files": [
"bootstrap.php"
],
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-07-28T13:41:28+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb",
"reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"psr/container": "^1.1"
},
"suggest": {
"symfony/service-implementation": ""
@@ -1902,7 +2832,11 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
"dev-main": "2.4-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
@@ -1934,27 +2868,178 @@
"interoperability",
"standards"
],
"time": "2019-11-18T17:27:11+00:00"
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v2.4.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-04-01T10:43:52+00:00"
},
{
"name": "vlucas/valitron",
"version": "v1.4.7",
"name": "symfony/string",
"version": "v5.3.3",
"source": {
"type": "git",
"url": "https://github.com/vlucas/valitron.git",
"reference": "a03072bed1679660200766d134507a30193eaf6d"
"url": "https://github.com/symfony/string.git",
"reference": "bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vlucas/valitron/zipball/a03072bed1679660200766d134507a30193eaf6d",
"reference": "a03072bed1679660200766d134507a30193eaf6d",
"url": "https://api.github.com/repos/symfony/string/zipball/bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1",
"reference": "bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-intl-grapheme": "~1.0",
"symfony/polyfill-intl-normalizer": "~1.0",
"symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php80": "~1.15"
},
"require-dev": {
"symfony/error-handler": "^4.4|^5.0",
"symfony/http-client": "^4.4|^5.0",
"symfony/translation-contracts": "^1.1|^2",
"symfony/var-exporter": "^4.4|^5.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\String\\": ""
},
"files": [
"Resources/functions.php"
],
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
"homepage": "https://symfony.com",
"keywords": [
"grapheme",
"i18n",
"string",
"unicode",
"utf-8",
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v5.3.3"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-06-27T11:44:38+00:00"
},
{
"name": "tysonandre/var_representation_polyfill",
"version": "0.0.2",
"source": {
"type": "git",
"url": "https://github.com/TysonAndre/var_representation_polyfill.git",
"reference": "3f17999ee1f257319ddc6721dd26ebbc5d175f33"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/TysonAndre/var_representation_polyfill/zipball/3f17999ee1f257319ddc6721dd26ebbc5d175f33",
"reference": "3f17999ee1f257319ddc6721dd26ebbc5d175f33",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": "^7.2.0|^8.0.0"
},
"require-dev": {
"phan/phan": "^4.0",
"phpunit/phpunit": "^8.5.0"
},
"type": "library",
"autoload": {
"psr-4": {
"VarRepresentation\\": "src/VarRepresentation"
},
"files": [
"src/var_representation.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Tyson Andre"
}
],
"description": "Polyfill for var_representation",
"keywords": [
"var_export",
"var_representation"
],
"support": {
"issues": "https://github.com/TysonAndre/var_representation_polyfill/issues",
"source": "https://github.com/TysonAndre/var_representation_polyfill/tree/0.0.2"
},
"time": "2021-06-26T18:55:02+00:00"
},
{
"name": "vlucas/valitron",
"version": "v1.4.10",
"source": {
"type": "git",
"url": "https://github.com/vlucas/valitron.git",
"reference": "5ebd5d7af82cc0a9d798e816a2ecad63f1b59ceb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vlucas/valitron/zipball/5ebd5d7af82cc0a9d798e816a2ecad63f1b59ceb",
"reference": "5ebd5d7af82cc0a9d798e816a2ecad63f1b59ceb",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.5 || ^6.5"
"phpunit/phpunit": ">=4.8.35"
},
"suggest": {
"ext-mbstring": "It can support the multiple bytes string length."
@@ -1973,43 +3058,59 @@
{
"name": "Vance Lucas",
"email": "vance@vancelucas.com",
"homepage": "http://www.vancelucas.com"
"homepage": "https://www.vancelucas.com"
}
],
"description": "Simple, elegant, stand-alone validation library with NO dependencies",
"homepage": "http://github.com/vlucas/valitron",
"homepage": "https://github.com/vlucas/valitron",
"keywords": [
"valid",
"validation",
"validator"
],
"time": "2019-08-29T19:49:43+00:00"
"support": {
"issues": "https://github.com/vlucas/valitron/issues",
"source": "https://github.com/vlucas/valitron/tree/v1.4.10"
},
"funding": [
{
"url": "https://tidelift.com/funding/github/packagist/vlucas/valitron",
"type": "tidelift"
}
],
"time": "2021-07-08T16:18:03+00:00"
},
{
"name": "webmozart/assert",
"version": "1.8.0",
"version": "1.10.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
"reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6"
"url": "https://github.com/webmozarts/assert.git",
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/assert/zipball/ab2cb0b3b559010b75981b1bdce728da3ee90ad6",
"reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25",
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0",
"php": "^7.2 || ^8.0",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"vimeo/psalm": "<3.9.1"
"phpstan/phpstan": "<0.12.20",
"vimeo/psalm": "<4.6.1 || 4.6.2"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36 || ^7.5.13"
"phpunit/phpunit": "^8.5.13"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.10-dev"
}
},
"autoload": {
"psr-4": {
"Webmozart\\Assert\\": "src/"
@@ -2031,7 +3132,11 @@
"check",
"validate"
],
"time": "2020-04-18T12:12:48+00:00"
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/1.10.0"
},
"time": "2021-03-09T10:59:23+00:00"
},
{
"name": "xemlock/htmlpurifier-html5",
@@ -2082,6 +3187,10 @@
"validator",
"xss"
],
"support": {
"issues": "https://github.com/xemlock/htmlpurifier-html5/issues",
"source": "https://github.com/xemlock/htmlpurifier-html5/tree/master"
},
"time": "2019-08-07T17:19:21+00:00"
}
],
@@ -2096,5 +3205,5 @@
"platform-overrides": {
"php": "7.3"
},
"plugin-api-version": "1.1.0"
"plugin-api-version": "2.0.0"
}
Regular → Executable
BIN
View File
Binary file not shown.
+240 -181
View File
@@ -1,182 +1,241 @@
@charset "utf-8";
body {
color:white; background-color:black; font-family: '맑은 고딕';
}
table {
border: solid 1px; border-spacing: 0px; border-collapse: separate; border-top-color: gray; border-left-color: gray; border-right-color: black; border-bottom-color: black;
padding: 0px;
font-size: 13px;
word-break: break-all;
text-align: center;
font-family: '맑은 고딕';
}
th, td {
border: solid 1px; border-spacing: 0px; border-collapse: separate; border-top-color: gray; border-left-color: gray; border-right-color: black; border-bottom-color: black;
padding: 0px;
font-size: 13px;
word-break: break-all;
text-align: center;
font-family: '맑은 고딕';
}
a.just_link {
text-decoration: none;
}
.with_border{
margin:0;
border: solid 1px;
border-spacing: 0px;
border-collapse: separate;
border-top-color: gray;
border-left-color: gray;
border-right-color: black;
border-bottom-color: black;
}
.section_title {
height:50px;
line-height:50px;
font-size: 30px; font-weight: bold;
text-align: center;
color:white;
padding:0;
}
.legacy_layout div {
border: solid 1px; border-spacing: 0px; border-collapse: separate; border-top-color: gray; border-left-color: gray; border-right-color: black; border-bottom-color: black;
padding: 0px;
font-size: 13px;
word-break: break-all;
text-align: center;
font-family: '맑은 고딕';;
}
.obj_fill{
display:block;
width:100%;
height:100%;
}
button.with_skin {
padding:0 4px;
background-color: black; color: white;
font-family: '맑은 고딕';
font-size: 13px;
}
button.with_skin:disabled {
background-color:#333333;
}
input.with_skin {
background-color: black; color: white;
font-family: '맑은 고딕';
font-size: 13px;
}
input.with_skin:disabled {
background-color: #333333;
}
.font0 { font-size: 10px; }
.font1 { font-size: 13px; }
.font2 { font-size: 15px; }
.font3 { font-size: 20px; }
.font4 { font-size: 30px; }
.font5 { font-size: 50px; }
caption.section_title {
caption-side:top;
}
.samButton{
float:left;
display:block;
padding:0;
margin:0;
text-decoration: none;
position:relative;
}
a.samButton.disabled {
pointer-events: none;
cursor: default;
}
.samButtonOuter{
display: table;
border: outset 2px white;
box-sizing: border-box;
font-weight:bold;
padding: 1px 6px;
width:125px;
height:30px;
background-color:#000000;
color:#ffffff;
}
.samButtonOuter:active{
border: inset 2px white;
}
.samButtonInner{
display: table-cell;
vertical-align: middle;
width: 100%;
margin: 0 auto;
text-align: center;
user-select: none;
}
.samToolbarButton > .samButtonOuter{
width:125px;
height:30px;
background-color:#225500;
color:white;
}
.samToolbarButton2 > .samButtonOuter{
width:125px;
height:30px;
background-color:#225500;
color:magenta;
}
.samCommandButton > .samButtonOuter{
width:111px;
height:30px;
}
.samCommandButton.disabled > .samButtonOuter{
background-color:transparent !important;
color:gray !important;
border-color:transparent !important;
}
.samCommandButton.disabled > .samButtonOuter > .samButtonInner::before{
content:'【'
}
.samCommandButton.disabled > .samButtonOuter > .samButtonInner::after{
content:'】'
}
.tooltip_copyable_info .tooltiptext{
display: inline;
color: rgba(0,0,0,0);
font-size: 0;
}
.tooltiptext {
display: none;
}
.hidden_but_copyable{
color: rgba(0,0,0,0);
font-size: 0;
@charset "utf-8";
body {
color: white;
background-color: black;
font-family: '맑은 고딕';
}
table {
border: solid 1px;
border-spacing: 0px;
border-collapse: separate;
border-top-color: gray;
border-left-color: gray;
border-right-color: black;
border-bottom-color: black;
padding: 0px;
font-size: 13px;
word-break: break-all;
text-align: center;
font-family: '맑은 고딕';
}
th,
td {
border: solid 1px;
border-spacing: 0px;
border-collapse: separate;
border-top-color: gray;
border-left-color: gray;
border-right-color: black;
border-bottom-color: black;
padding: 0px;
font-size: 13px;
word-break: break-all;
text-align: center;
font-family: '맑은 고딕';
}
a.just_link {
text-decoration: none;
}
.with_border {
margin: 0;
border: solid 1px;
border-spacing: 0px;
border-collapse: separate;
border-top-color: gray;
border-left-color: gray;
border-right-color: black;
border-bottom-color: black;
}
.section_title {
height: 50px;
line-height: 50px;
font-size: 30px;
font-weight: bold;
text-align: center;
color: white;
padding: 0;
}
.legacy_layout div {
border: solid 1px;
border-spacing: 0px;
border-collapse: separate;
border-top-color: gray;
border-left-color: gray;
border-right-color: black;
border-bottom-color: black;
padding: 0px;
font-size: 13px;
word-break: break-all;
text-align: center;
font-family: '맑은 고딕';
;
}
.obj_fill {
display: block;
width: 100%;
height: 100%;
}
button.with_skin {
padding: 0 4px;
background-color: black;
color: white;
font-family: '맑은 고딕';
font-size: 13px;
}
button.with_skin:disabled {
background-color: #333333;
}
input.with_skin {
background-color: black;
color: white;
font-family: '맑은 고딕';
font-size: 13px;
}
input.with_skin:disabled {
background-color: #333333;
}
.font0 {
font-size: 10px;
}
.font1 {
font-size: 13px;
}
.font2 {
font-size: 15px;
}
.font3 {
font-size: 20px;
}
.font4 {
font-size: 30px;
}
.font5 {
font-size: 50px;
}
caption.section_title {
caption-side: top;
}
.samButton {
float: left;
display: block;
padding: 0;
margin: 0;
text-decoration: none;
position: relative;
}
a.samButton.disabled {
pointer-events: none;
cursor: default;
}
.samButtonOuter {
display: table;
border: outset 2px white;
box-sizing: border-box;
font-weight: bold;
padding: 1px 6px;
width: 125px;
height: 30px;
background-color: #000000;
color: #ffffff;
}
.samButtonOuter:active {
border: inset 2px white;
}
.samButtonInner {
display: table-cell;
vertical-align: middle;
width: 100%;
margin: 0 auto;
text-align: center;
user-select: none;
}
.samToolbarButton>.samButtonOuter {
width: 125px;
height: 30px;
background-color: #225500;
color: white;
}
.samToolbarButton2>.samButtonOuter {
width: 125px;
height: 30px;
background-color: #225500;
color: magenta;
}
.samCommandButton>.samButtonOuter {
width: 111px;
height: 30px;
}
.samCommandButton.disabled>.samButtonOuter {
background-color: transparent !important;
color: gray !important;
border-color: transparent !important;
}
.samCommandButton.disabled>.samButtonOuter>.samButtonInner::before {
content: '【'
}
.samCommandButton.disabled>.samButtonOuter>.samButtonInner::after {
content: '】'
}
.tooltip_copyable_info .tooltiptext {
display: inline;
color: rgba(0, 0, 0, 0);
font-size: 0;
}
.tooltiptext {
display: none;
}
.hidden_but_copyable {
color: rgba(0, 0, 0, 0);
font-size: 0;
}
.vertical_flex {
height: 100%;
display: flex;
align-content: center;
flex-direction: column;
align-items: stretch;
}
.vertical_flex .item {
display: block;
flex-grow: 1;
}
.fill_box {
display: block;
width: 100%;
height: 100%;
}
+155 -140
View File
@@ -1,141 +1,156 @@
@charset "utf-8";
body{
line-height: 1.3;
}
#server_notice {
margin:10px 0;
border: none;
text-align:center;
}
#server_list_container{
width:800px;
position:absolute;
left:50%;
margin-left:-400px;
}
#server_list_table{
width:100%;
}
#server_list tr{
height:66px;
}
#server_list .server_create_and_select .general_create,
#server_list .server_create_and_select .general_select {
width: 120px; height: 33px;
float: left;
}
#server_list .general_create,
#server_list .general_login {
width: 120px; height: 66px;
float: left;
}
.ignore_border{
border:0;
margin:0;
padding:0;
}
#user_info {
margin-top:20px;
width: 800px; height: 130px;
}
#user_info button{
width: 200px;
height: 50px;
margin: 10px 50px;
}
.center_ordered_items{
text-align:center;
}
.Entrance_ServerList {
width: 800px; height: 64px;
border: none;
float: left;
}
.Entrance_ServerListServer {
width: 98px; height: 64px;
float: left;
}
.Entrance_ServerListDown {
width: 698px; height: 64px;
float: left;
}
.Entrance_ServerListInfo {
width: 398px; height: 64px;
float: left;
}
.Entrance_ServerListBlock {
width: 298px; height: 64px;
float: left;
line-height: 64px;
}
.Entrance_ServerListCharacter {
width: 64px; height: 64px;
float: left;
}
.Entrance_ServerListName {
width: 112px; height: 64px;
float: left;
line-height: 64px;
}
.Entrance_ServerListSelect {
width: 120px; height: 32px;
float: left;
}
#Entrance_000003 {
width: 798px; height: 155px;
text-align: left;
}
.Entrance_Alert {
color: red; font-size: 15px; font-weight: bold;
}
.Entrance_Che {
color: white; font-size: 15px; font-weight: bold;
}
.Entrance_Kwe {
color: yellow; font-size: 15px; font-weight: bold;
}
.Entrance_Pwe {
color: orange; font-size: 15px; font-weight: bold;
}
.Entrance_Twe {
color: magenta; font-size: 15px; font-weight: bold;
}
.Entrance_Nya {
color: #e67e22; font-size: 15px; font-weight: bold;
}
.Entrance_Pya {
color: #9b59b6; font-size: 15px; font-weight: bold;
}
.Entrance_Hwe {
color: red; font-size: 15px; font-weight: bold;
@charset "utf-8";
body {
line-height: 1.3;
}
#server_notice {
margin: 10px 0;
border: none;
text-align: center;
}
#server_list_container {
width: 800px;
position: absolute;
left: 50%;
margin-left: -400px;
}
#server_list_table {
width: 100%;
}
#server_list tr {
height: 66px;
}
.ignore_border {
border: 0;
margin: 0;
padding: 0;
}
#user_info {
margin-top: 20px;
width: 800px;
height: 130px;
}
#user_info button {
width: 200px;
height: 50px;
margin: 10px 50px;
}
.center_ordered_items {
text-align: center;
}
.Entrance_ServerList {
width: 800px;
height: 64px;
border: none;
float: left;
}
.Entrance_ServerListServer {
width: 98px;
height: 64px;
float: left;
}
.Entrance_ServerListDown {
width: 698px;
height: 64px;
float: left;
}
.Entrance_ServerListInfo {
width: 398px;
height: 64px;
float: left;
}
.Entrance_ServerListBlock {
width: 298px;
height: 64px;
float: left;
line-height: 64px;
}
.Entrance_ServerListCharacter {
width: 64px;
height: 64px;
float: left;
}
.Entrance_ServerListName {
width: 112px;
height: 64px;
float: left;
line-height: 64px;
}
.Entrance_ServerListSelect {
width: 120px;
height: 32px;
float: left;
}
#Entrance_000003 {
width: 798px;
height: 155px;
text-align: left;
}
.Entrance_Alert {
color: red;
font-size: 15px;
font-weight: bold;
}
.Entrance_Che {
color: white;
font-size: 15px;
font-weight: bold;
}
.Entrance_Kwe {
color: yellow;
font-size: 15px;
font-weight: bold;
}
.Entrance_Pwe {
color: orange;
font-size: 15px;
font-weight: bold;
}
.Entrance_Twe {
color: magenta;
font-size: 15px;
font-weight: bold;
}
.Entrance_Nya {
color: #e67e22;
font-size: 15px;
font-weight: bold;
}
.Entrance_Pya {
color: #9b59b6;
font-size: 15px;
font-weight: bold;
}
.Entrance_Hwe {
color: red;
font-size: 15px;
font-weight: bold;
}
.BtnPlate {
height: inherit;
}
+131 -130
View File
@@ -1,131 +1,132 @@
body, html{
height: 100%;
background-repeat: no-repeat;
}
.main{
margin-top: 70px;
}
h1.title {
font-size: 50px;
font-family: 'Passion One', cursive;
font-weight: 400;
}
hr{
width: 10%;
/*color: #fff;*/
}
.form-group{
margin-bottom: 15px;
}
label{
margin-bottom: 15px;
}
input,
input::-webkit-input-placeholder {
font-size: 11px;
padding-top: 3px;
}
.main-login{
/*background-color: #fff;*/
/* shadows and rounded borders */
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
}
.main-center{
margin-top: 30px;
margin: 0 auto;
max-width: 330px;
padding: 40px 40px;
}
.login_btn_group{
margin-top: 5px;
}
.login-register{
font-size: 11px;
text-align: center;
}
.col-form-label{
text-align:center;
}
.terms{
max-height: 200px; overflow-y: auto;
}
.terms pre{
width:100%;
white-space: pre-wrap; /* Since CSS 2.1 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
.vertical-center {
min-height: 100%; /* Fallback for browsers do NOT support vh unit */
min-height: 100vh; /* These two lines are counted as one :-) */
display: flex;
align-items: center;
}
.full-content {
position:fixed;
left:0;
top:0;
width:100%;
height:100%;
margin:0;
padding:0;
z-index:800;
}
#login_card{
z-index:801;
}
#btn_kakao_login{
cursor: pointer;
height:46px;
width:116px;
background-color: transparent;
color:transparent;
border:0;
background-size: 100%; /* To fill the dimensions of container (button), or */
background-repeat: no-repeat;
background-position: bottom center;
margin-top:5px;
background-image:url('../oauth_kakao/kakao_login_join.png');
}
#btn_kakao_login:hover {
background-image:url('../oauth_kakao/kakao_login_join_ov.png');
}
#bottom_box{
position:fixed;
bottom:0;
width:100%;
left:0;
}
#bottom_box .container{
text-align:center;
body,
html {
height: 100%;
background-repeat: no-repeat;
}
.main {
margin-top: 70px;
}
h1.title {
font-size: 50px;
font-family: 'Passion One', cursive;
font-weight: 400;
}
hr {
width: 10%;
/*color: #fff;*/
}
.form-group {
margin-bottom: 15px;
}
label {
margin-bottom: 15px;
}
input,
input::-webkit-input-placeholder {
font-size: 11px;
padding-top: 3px;
}
.main-login {
/*background-color: #fff;*/
/* shadows and rounded borders */
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
}
.main-center {
margin-top: 30px;
margin: 0 auto;
max-width: 330px;
padding: 40px 40px;
}
.login_btn_group {
margin-top: 5px;
}
.login-register {
font-size: 11px;
text-align: center;
}
.col-form-label {
text-align: center;
}
.terms {
max-height: 200px;
overflow-y: auto;
}
.terms pre {
width: 100%;
white-space: pre-wrap;
/* Since CSS 2.1 */
white-space: -moz-pre-wrap;
/* Mozilla, since 1999 */
white-space: -pre-wrap;
/* Opera 4-6 */
white-space: -o-pre-wrap;
/* Opera 7 */
word-wrap: break-word;
/* Internet Explorer 5.5+ */
}
.vertical-center {
min-height: 100%;
/* Fallback for browsers do NOT support vh unit */
min-height: 100vh;
/* These two lines are counted as one :-) */
display: flex;
align-items: center;
}
#login_card {
z-index: 801;
}
#btn_kakao_login {
cursor: pointer;
height: 46px;
width: 116px;
background-color: transparent;
color: transparent;
border: 0;
background-size: 100%;
/* To fill the dimensions of container (button), or */
background-repeat: no-repeat;
background-position: bottom center;
margin-top: 5px;
background-image: url('../oauth_kakao/kakao_login_join.png');
}
#btn_kakao_login:hover {
background-image: url('../oauth_kakao/kakao_login_join_ov.png');
}
#bottom_box .container {
text-align: center;
}
.btn-group-xs>.btn,
.btn-xs {
padding: .25rem .4rem;
font-size: .875rem;
line-height: .5;
border-radius: .2rem;
}
#running_map {
margin-top: 20px;
}
+2 -2
View File
@@ -1,3 +1,3 @@
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="너무 깁니다. "+t+" 글자 지워주세요.";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="너무 짧습니다. "+t+" 글자 더 입력해주세요.";return n},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(e){var t="최대 "+e.maximum+"개까지만 선택 가능합니다.";return t},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"}}}),{define:e.define,require:e.require}})();
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(n){return"너무 깁니다. "+(n.input.length-n.maximum)+" 글자 지워주세요."},inputTooShort:function(n){return"너무 짧습니다. "+(n.minimum-n.input.length)+" 글자 더 입력해주세요."},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(n){return"최대 "+n.maximum+"개까지만 선택 가능합니다."},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"},removeAllItems:function(){return"모든 항목 삭제"}}}),n.define,n.require}();
+553 -188
View File
@@ -1,188 +1,553 @@
/* select2-bootstrap4 with Darkly */
.select2-container--bootstrap4 { color: black; }
.select2-container--bootstrap4 .select2-selection { background-color: #fff; border: 1px solid #ced4da; border-radius: 0.25rem; color: #495057; font-size: 1rem; outline: 0; }
.select2-container--bootstrap4 .select2-selection.form-control { border-radius: 0.25rem; }
.select2-container--bootstrap4 .select2-search--dropdown .select2-search__field { background-color: #fff; border: 1px solid #ced4da; border-radius: 0.25rem; color: #495057; font-size: 1rem; }
.select2-container--bootstrap4 .select2-search__field { outline: 0; }
.select2-container--bootstrap4 .select2-search__field::-webkit-input-placeholder { color: #6c757d; }
.select2-container--bootstrap4 .select2-search__field:-moz-placeholder { color: #6c757d; }
.select2-container--bootstrap4 .select2-search__field::-moz-placeholder { color: #6c757d; opacity: 1; }
.select2-container--bootstrap4 .select2-search__field:-ms-input-placeholder { color: #6c757d; }
.select2-container--bootstrap4 .select2-results__option { padding: 0.75rem 0.375rem; font-size: 1rem; }
.select2-container--bootstrap4 .select2-results__option[role=group] { padding: 0; }
.select2-container--bootstrap4 .select2-results__option[aria-disabled=true] { color: #6c757d; cursor: not-allowed; }
.select2-container--bootstrap4 .select2-results__option[aria-selected=true] { background-color: #f8f9fa; color: #16181b; }
.select2-container--bootstrap4 .select2-results__option--highlighted[aria-selected] { background-color: #007bff; color: #fff; }
.select2-container--bootstrap4 .select2-results__option .select2-results__option { padding: 0.75rem 0.375rem; }
.select2-container--bootstrap4 .select2-results__option .select2-results__option .select2-results__group { padding-left: 0; }
.select2-container--bootstrap4 .select2-results__option .select2-results__option .select2-results__option { margin-left: -0.375rem; padding-left: 0.75rem; }
.select2-container--bootstrap4 .select2-results__option .select2-results__option .select2-results__option .select2-results__option { margin-left: -0.75rem; padding-left: 1.125rem; }
.select2-container--bootstrap4 .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { margin-left: -1.125rem; padding-left: 1.5rem; }
.select2-container--bootstrap4 .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { margin-left: -1.5rem; padding-left: 1.875rem; }
.select2-container--bootstrap4 .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { margin-left: -1.875rem; padding-left: 2.25rem; }
.select2-container--bootstrap4 .select2-results__group { color: #6c757d; display: block; padding: 0.75rem 0.375rem; font-size: 75%; line-height: 1; white-space: nowrap; }
.select2-container--bootstrap4.select2-container--focus .select2-selection, .select2-container--bootstrap4.select2-container--open .select2-selection { transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; border-color: #80bdff; }
@media screen and (prefers-reduced-motion: reduce) { .select2-container--bootstrap4.select2-container--focus .select2-selection, .select2-container--bootstrap4.select2-container--open .select2-selection { transition: none; } }
.select2-container--bootstrap4.select2-container--open .select2-selection .select2-selection__arrow b { border-color: transparent transparent #6c757d transparent; border-width: 0 0.25rem 0.25rem 0.25rem; }
.select2-container--bootstrap4.select2-container--open.select2-container--below .select2-selection { border-bottom-right-radius: 0; border-bottom-left-radius: 0; border-bottom-color: transparent; }
.select2-container--bootstrap4.select2-container--open.select2-container--above .select2-selection { border-top-left-radius: 0; border-top-right-radius: 0; border-top-color: transparent; }
.select2-container--bootstrap4 .select2-selection__clear { color: #6c757d; cursor: pointer; float: right; font-weight: bold; margin-right: 10px; }
.select2-container--bootstrap4 .select2-selection__clear:hover { color: #343a40; }
.select2-container--bootstrap4.select2-container--disabled .select2-selection { border-color: #ced4da; }
.select2-container--bootstrap4.select2-container--disabled .select2-selection, .select2-container--bootstrap4.select2-container--disabled .select2-search__field { cursor: not-allowed; }
.select2-container--bootstrap4.select2-container--disabled .select2-selection, .select2-container--bootstrap4.select2-container--disabled .select2-selection--multiple .select2-selection__choice { background-color: #e9ecef; }
.select2-container--bootstrap4.select2-container--disabled .select2-selection__clear, .select2-container--bootstrap4.select2-container--disabled .select2-selection--multiple .select2-selection__choice__remove { display: none; }
.select2-container--bootstrap4 .select2-dropdown { border-color: #80bdff; border-width: 1px; overflow-x: hidden; margin-top: -1px; }
.select2-container--bootstrap4 .select2-dropdown--above { margin-top: 1px; }
.select2-container--bootstrap4 .select2-results > .select2-results__options { max-height: 200px; overflow-y: auto; }
.select2-container--bootstrap4 .select2-selection--single { height: calc(2.25rem + 2px); line-height: 1; padding: 0.75rem 1.125rem 0.75rem 0.375rem; }
.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow { position: absolute; bottom: 0; right: 0.375rem; top: 0; width: 0.25rem; }
.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b { border-color: #6c757d transparent transparent transparent; border-style: solid; border-width: 0.25rem 0.25rem 0 0.25rem; height: 0; left: 0; margin-left: -0.25rem; margin-top: -0.125rem; position: absolute; top: 50%; width: 0; }
.select2-container--bootstrap4 .select2-selection--single .select2-selection__rendered { color: #495057; padding: 0; }
.select2-container--bootstrap4 .select2-selection--single .select2-selection__placeholder { color: #6c757d; }
.select2-container--bootstrap4 .select2-selection--multiple { min-height: calc(2.25rem + 2px); padding: 0; height: auto; }
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__rendered { box-sizing: border-box; display: block; line-height: 1; list-style: none; margin: 0; overflow: hidden; padding: 0.75rem 0.375rem 0 0.75rem; width: 100%; text-overflow: ellipsis; white-space: nowrap; }
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__placeholder { color: #6c757d; float: left; margin-top: 5px; }
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice { color: #495057; background: transparent; border: 1px solid #343a40; border-radius: 0.25rem; cursor: default; float: left; margin: -0.25rem 0 0 0.1875rem; padding: 0 0.75rem; }
.select2-container--bootstrap4 .select2-selection--multiple .select2-search--inline .select2-search__field { background: transparent; padding: 0 0.375rem; height: calc(2.25rem + 2px)-2; line-height: 1; margin-top: 0; min-width: 5em; }
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove { color: #6c757d; cursor: pointer; display: inline-block; font-weight: bold; margin-right: 0.375rem; }
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove:hover { color: #343a40; }
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__clear { margin-top: 0.75rem; }
.select2-container--bootstrap4 .select2-selection--single.input-sm, .input-group-sm .select2-container--bootstrap4 .select2-selection--single, .form-group-sm .select2-container--bootstrap4 .select2-selection--single { border-radius: 0.2rem; font-size: 75%; height: calc(1.8125rem + 2px); line-height: 1; padding: 0.5rem 1rem 0.5rem 0.25rem; }
.select2-container--bootstrap4 .select2-selection--single.input-sm .select2-selection__arrow b, .input-group-sm .select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b, .form-group-sm .select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b { margin-left: -0.5rem; }
.select2-container--bootstrap4 .select2-selection--multiple.input-sm, .input-group-sm .select2-container--bootstrap4 .select2-selection--multiple, .form-group-sm .select2-container--bootstrap4 .select2-selection--multiple { min-height: calc(1.8125rem + 2px); border-radius: 0.2rem; }
.select2-container--bootstrap4 .select2-selection--multiple.input-sm .select2-selection__rendered, .input-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__rendered, .form-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__rendered { padding: 0.5rem 0.25rem 0 0.5rem; }
.select2-container--bootstrap4 .select2-selection--multiple.input-sm .select2-selection__choice, .input-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice, .form-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice { font-size: 75%; line-height: 1; margin: 0 0 0 0.125rem; padding: 0 0.5rem; }
.select2-container--bootstrap4 .select2-selection--multiple.input-sm .select2-search--inline .select2-search__field, .input-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-search--inline .select2-search__field, .form-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-search--inline .select2-search__field { padding: 0 0.25rem; font-size: 75%; height: calc(1.8125rem + 2px)-2; line-height: 1; }
.select2-container--bootstrap4 .select2-selection--multiple.input-sm .select2-selection__clear, .input-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__clear, .form-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__clear { margin-top: 0.5rem; }
.select2-container--bootstrap4 .select2-selection--single.input-lg, .input-group-lg .select2-container--bootstrap4 .select2-selection--single, .form-group-lg .select2-container--bootstrap4 .select2-selection--single { border-radius: 0.3rem; font-size: 1.25rem; height: calc(2.875rem + 2px); line-height: 1; padding: 1rem 1.4375rem 1rem 0.5rem; }
.select2-container--bootstrap4 .select2-selection--single.input-lg .select2-selection__arrow, .input-group-lg .select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow, .form-group-lg .select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow { width: 0.3125rem; }
.select2-container--bootstrap4 .select2-selection--single.input-lg .select2-selection__arrow b, .input-group-lg .select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b, .form-group-lg .select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b { border-width: 0.3125rem 0.3125rem 0 0.3125rem; margin-left: -0.3125rem; margin-left: -1rem; margin-top: -0.15625rem; }
.select2-container--bootstrap4 .select2-selection--multiple.input-lg, .input-group-lg .select2-container--bootstrap4 .select2-selection--multiple, .form-group-lg .select2-container--bootstrap4 .select2-selection--multiple { min-height: calc(2.875rem + 2px); border-radius: 0.3rem; }
.select2-container--bootstrap4 .select2-selection--multiple.input-lg .select2-selection__choice, .input-group-lg .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice, .form-group-lg .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice { font-size: 1.25rem; line-height: 1; border-radius: 0.25rem; margin: 0rem 0 0 0.25rem; padding: 0 1rem; }
.select2-container--bootstrap4 .select2-selection--multiple.input-lg .select2-search--inline .select2-search__field, .input-group-lg .select2-container--bootstrap4 .select2-selection--multiple .select2-search--inline .select2-search__field, .form-group-lg .select2-container--bootstrap4 .select2-selection--multiple .select2-search--inline .select2-search__field { padding: 0 0.5rem; font-size: 1.25rem; height: calc(2.875rem + 2px)-2; line-height: 1; }
.select2-container--bootstrap4 .select2-selection--multiple.input-lg .select2-selection__clear, .input-group-lg .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__clear, .form-group-lg .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__clear { margin-top: 1rem; }
.select2-container--bootstrap4 .select2-selection.input-lg.select2-container--open .select2-selection--single .select2-selection__arrow b { border-color: transparent transparent #6c757d transparent; border-width: 0 0.3125rem 0.3125rem 0.3125rem; }
.input-group-lg .select2-container--bootstrap4 .select2-selection.select2-container--open .select2-selection--single .select2-selection__arrow b { border-color: transparent transparent #6c757d transparent; border-width: 0 0.3125rem 0.3125rem 0.3125rem; }
.select2-container--bootstrap4[dir="rtl"] .select2-selection--single { padding-left: 1.125rem; padding-right: 0.375rem; }
.select2-container--bootstrap4[dir="rtl"] .select2-selection--single .select2-selection__rendered { padding-right: 0; padding-left: 0; text-align: right; }
.select2-container--bootstrap4[dir="rtl"] .select2-selection--single .select2-selection__clear { float: left; }
.select2-container--bootstrap4[dir="rtl"] .select2-selection--single .select2-selection__arrow { left: 0.375rem; right: auto; }
.select2-container--bootstrap4[dir="rtl"] .select2-selection--single .select2-selection__arrow b { margin-left: 0; }
.select2-container--bootstrap4[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--bootstrap4[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--bootstrap4[dir="rtl"] .select2-selection--multiple .select2-search--inline { float: right; }
.select2-container--bootstrap4[dir="rtl"] .select2-selection--multiple .select2-selection__choice { margin-left: 0; margin-right: 0.1875rem; }
.select2-container--bootstrap4[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove { margin-left: 2px; margin-right: auto; }
.has-warning .select2-dropdown, .has-warning .select2-selection { border-color: #ffc107; }
.has-warning .select2-container--focus .select2-selection, .has-warning .select2-container--open .select2-selection { border-color: #d39e00; }
.has-warning.select2-drop-active { border-color: #d39e00; }
.has-warning.select2-drop-active.select2-drop.select2-drop-above { border-top-color: #d39e00; }
.has-error .select2-dropdown, .has-error .select2-selection { border-color: #dc3545; }
.has-error .select2-container--focus .select2-selection, .has-error .select2-container--open .select2-selection { border-color: #bd2130; }
.has-error.select2-drop-active { border-color: #bd2130; }
.has-error.select2-drop-active.select2-drop.select2-drop-above { border-top-color: #bd2130; }
.has-success .select2-dropdown, .has-success .select2-selection { border-color: #28a745; }
.has-success .select2-container--focus .select2-selection, .has-success .select2-container--open .select2-selection { border-color: #1e7e34; }
.has-success.select2-drop-active { border-color: #1e7e34; }
.has-success.select2-drop-active.select2-drop.select2-drop-above { border-top-color: #1e7e34; }
.input-group > .select2-hidden-accessible:first-child + .select2-container--bootstrap4 > .selection > .select2-selection, .input-group > .select2-hidden-accessible:first-child + .select2-container--bootstrap4 > .selection > .select2-selection.form-control { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.input-group > .select2-hidden-accessible:not(:first-child) + .select2-container--bootstrap4:not(:last-child) > .selection > .select2-selection, .input-group > .select2-hidden-accessible:not(:first-child) + .select2-container--bootstrap4:not(:last-child) > .selection > .select2-selection.form-control { border-radius: 0; }
.input-group > .select2-hidden-accessible:not(:first-child):not(:last-child) + .select2-container--bootstrap4:last-child > .selection > .select2-selection, .input-group > .select2-hidden-accessible:not(:first-child):not(:last-child) + .select2-container--bootstrap4:last-child > .selection > .select2-selection.form-control { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.input-group > .select2-container--bootstrap4 { display: table; table-layout: fixed; position: relative; z-index: 2; width: 100%; margin-bottom: 0; }
.input-group > .select2-container--bootstrap4 > .selection > .select2-selection.form-control { float: none; }
.input-group > .select2-container--bootstrap4.select2-container--open, .input-group > .select2-container--bootstrap4.select2-container--focus { z-index: 3; }
.input-group > .select2-container--bootstrap4, .input-group > .select2-container--bootstrap4 .input-group-btn, .input-group > .select2-container--bootstrap4 .input-group-btn .btn { vertical-align: top; }
.form-control.select2-hidden-accessible { position: absolute !important; width: 1px !important; }
@media (min-width: 576px) { .form-inline .select2-container--bootstrap4 { display: inline-block; } }
/* select2-bootstrap4 with Darkly */
.select2-container--bootstrap4 {
color: black;
}
.select2-container--bootstrap4 .select2-selection {
background-color: #fff;
border: 1px solid #ced4da;
border-radius: 0.25rem;
color: #495057;
font-size: 1rem;
outline: 0;
}
.select2-container--bootstrap4 .select2-selection.form-control {
border-radius: 0.25rem;
}
.select2-container--bootstrap4 .select2-search--dropdown .select2-search__field {
background-color: #fff;
border: 1px solid #ced4da;
border-radius: 0.25rem;
color: #495057;
font-size: 1rem;
}
.select2-container--bootstrap4 .select2-search__field {
outline: 0;
}
.select2-container--bootstrap4 .select2-search__field::-webkit-input-placeholder {
color: #6c757d;
}
.select2-container--bootstrap4 .select2-search__field:-moz-placeholder {
color: #6c757d;
}
.select2-container--bootstrap4 .select2-search__field::-moz-placeholder {
color: #6c757d;
opacity: 1;
}
.select2-container--bootstrap4 .select2-search__field:-ms-input-placeholder {
color: #6c757d;
}
.select2-container--bootstrap4 .select2-results__option {
padding: 0.75rem 0.375rem;
font-size: 1rem;
}
.select2-container--bootstrap4 .select2-results__option[role=group] {
padding: 0;
}
.select2-container--bootstrap4 .select2-results__option[aria-disabled=true] {
color: #6c757d;
cursor: not-allowed;
}
.select2-container--bootstrap4 .select2-results__option[aria-selected=true] {
background-color: #f8f9fa;
color: #16181b;
}
.select2-container--bootstrap4 .select2-results__option--highlighted[aria-selected] {
background-color: #007bff;
color: #fff;
}
.select2-container--bootstrap4 .select2-results__option .select2-results__option {
padding: 0.75rem 0.375rem;
}
.select2-container--bootstrap4 .select2-results__option .select2-results__option .select2-results__group {
padding-left: 0;
}
.select2-container--bootstrap4 .select2-results__option .select2-results__option .select2-results__option {
margin-left: -0.375rem;
padding-left: 0.75rem;
}
.select2-container--bootstrap4 .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
margin-left: -0.75rem;
padding-left: 1.125rem;
}
.select2-container--bootstrap4 .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
margin-left: -1.125rem;
padding-left: 1.5rem;
}
.select2-container--bootstrap4 .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
margin-left: -1.5rem;
padding-left: 1.875rem;
}
.select2-container--bootstrap4 .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
margin-left: -1.875rem;
padding-left: 2.25rem;
}
.select2-container--bootstrap4 .select2-results__group {
color: #6c757d;
display: block;
padding: 0.75rem 0.375rem;
font-size: 75%;
line-height: 1;
white-space: nowrap;
}
.select2-container--bootstrap4.select2-container--focus .select2-selection,
.select2-container--bootstrap4.select2-container--open .select2-selection {
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
border-color: #80bdff;
}
@media screen and (prefers-reduced-motion: reduce) {
.select2-container--bootstrap4.select2-container--focus .select2-selection,
.select2-container--bootstrap4.select2-container--open .select2-selection {
transition: none;
}
}
.select2-container--bootstrap4.select2-container--open .select2-selection .select2-selection__arrow b {
border-color: transparent transparent #6c757d transparent;
border-width: 0 0.25rem 0.25rem 0.25rem;
}
.select2-container--bootstrap4.select2-container--open.select2-container--below .select2-selection {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
border-bottom-color: transparent;
}
.select2-container--bootstrap4.select2-container--open.select2-container--above .select2-selection {
border-top-left-radius: 0;
border-top-right-radius: 0;
border-top-color: transparent;
}
.select2-container--bootstrap4 .select2-selection__clear {
color: #6c757d;
cursor: pointer;
float: right;
font-weight: bold;
margin-right: 10px;
}
.select2-container--bootstrap4 .select2-selection__clear:hover {
color: #343a40;
}
.select2-container--bootstrap4.select2-container--disabled .select2-selection {
border-color: #ced4da;
}
.select2-container--bootstrap4.select2-container--disabled .select2-selection,
.select2-container--bootstrap4.select2-container--disabled .select2-search__field {
cursor: not-allowed;
}
.select2-container--bootstrap4.select2-container--disabled .select2-selection,
.select2-container--bootstrap4.select2-container--disabled .select2-selection--multiple .select2-selection__choice {
background-color: #e9ecef;
}
.select2-container--bootstrap4.select2-container--disabled .select2-selection__clear,
.select2-container--bootstrap4.select2-container--disabled .select2-selection--multiple .select2-selection__choice__remove {
display: none;
}
.select2-container--bootstrap4 .select2-dropdown {
border-color: #80bdff;
border-width: 1px;
overflow-x: hidden;
margin-top: -1px;
}
.select2-container--bootstrap4 .select2-dropdown--above {
margin-top: 1px;
}
.select2-container--bootstrap4 .select2-results>.select2-results__options {
max-height: 200px;
overflow-y: auto;
}
.select2-container--bootstrap4 .select2-selection--single {
height: calc(2.25rem + 2px);
line-height: 1;
padding: 0.75rem 1.125rem 0.75rem 0.375rem;
}
.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow {
position: absolute;
bottom: 0;
right: 0.375rem;
top: 0;
width: 0.25rem;
}
.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b {
border-color: #6c757d transparent transparent transparent;
border-style: solid;
border-width: 0.25rem 0.25rem 0 0.25rem;
height: 0;
left: 0;
margin-left: -0.25rem;
margin-top: -0.125rem;
position: absolute;
top: 50%;
width: 0;
}
.select2-container--bootstrap4 .select2-selection--single .select2-selection__rendered {
color: #495057;
padding: 0;
}
.select2-container--bootstrap4 .select2-selection--single .select2-selection__placeholder {
color: #6c757d;
}
.select2-container--bootstrap4 .select2-selection--multiple {
min-height: calc(2.25rem + 2px);
padding: 0;
height: auto;
}
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__rendered {
box-sizing: border-box;
display: block;
line-height: 1;
list-style: none;
margin: 0;
overflow: hidden;
padding: 0.75rem 0.375rem 0 0.75rem;
width: 100%;
text-overflow: ellipsis;
white-space: nowrap;
}
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__placeholder {
color: #6c757d;
float: left;
margin-top: 5px;
}
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice {
color: #495057;
background: transparent;
border: 1px solid #343a40;
border-radius: 0.25rem;
cursor: default;
float: left;
margin: -0.25rem 0 0 0.1875rem;
padding: 0 0.75rem;
}
.select2-container--bootstrap4 .select2-selection--multiple .select2-search--inline .select2-search__field {
background: transparent;
padding: 0 0.375rem;
height: calc(2.25rem + 2px)-2;
line-height: 1;
margin-top: 0;
min-width: 5em;
}
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove {
color: #6c757d;
cursor: pointer;
display: inline-block;
font-weight: bold;
margin-right: 0.375rem;
}
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove:hover {
color: #343a40;
}
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__clear {
margin-top: 0.75rem;
}
.select2-container--bootstrap4 .select2-selection--single.input-sm,
.input-group-sm .select2-container--bootstrap4 .select2-selection--single,
.form-group-sm .select2-container--bootstrap4 .select2-selection--single {
border-radius: 0.2rem;
font-size: 75%;
height: calc(1.8125rem + 2px);
line-height: 1;
padding: 0.5rem 1rem 0.5rem 0.25rem;
}
.select2-container--bootstrap4 .select2-selection--single.input-sm .select2-selection__arrow b,
.input-group-sm .select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b,
.form-group-sm .select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b {
margin-left: -0.5rem;
}
.select2-container--bootstrap4 .select2-selection--multiple.input-sm,
.input-group-sm .select2-container--bootstrap4 .select2-selection--multiple,
.form-group-sm .select2-container--bootstrap4 .select2-selection--multiple {
min-height: calc(1.8125rem + 2px);
border-radius: 0.2rem;
}
.select2-container--bootstrap4 .select2-selection--multiple.input-sm .select2-selection__rendered,
.input-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__rendered,
.form-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__rendered {
padding: 0.5rem 0.25rem 0 0.5rem;
}
.select2-container--bootstrap4 .select2-selection--multiple.input-sm .select2-selection__choice,
.input-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice,
.form-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice {
font-size: 75%;
line-height: 1;
margin: 0 0 0 0.125rem;
padding: 0 0.5rem;
}
.select2-container--bootstrap4 .select2-selection--multiple.input-sm .select2-search--inline .select2-search__field,
.input-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-search--inline .select2-search__field,
.form-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-search--inline .select2-search__field {
padding: 0 0.25rem;
font-size: 75%;
height: calc(1.8125rem + 2px)-2;
line-height: 1;
}
.select2-container--bootstrap4 .select2-selection--multiple.input-sm .select2-selection__clear,
.input-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__clear,
.form-group-sm .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__clear {
margin-top: 0.5rem;
}
.select2-container--bootstrap4 .select2-selection--single.input-lg,
.input-group-lg .select2-container--bootstrap4 .select2-selection--single,
.form-group-lg .select2-container--bootstrap4 .select2-selection--single {
border-radius: 0.3rem;
font-size: 1.25rem;
height: calc(2.875rem + 2px);
line-height: 1;
padding: 1rem 1.4375rem 1rem 0.5rem;
}
.select2-container--bootstrap4 .select2-selection--single.input-lg .select2-selection__arrow,
.input-group-lg .select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow,
.form-group-lg .select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow {
width: 0.3125rem;
}
.select2-container--bootstrap4 .select2-selection--single.input-lg .select2-selection__arrow b,
.input-group-lg .select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b,
.form-group-lg .select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b {
border-width: 0.3125rem 0.3125rem 0 0.3125rem;
margin-left: -0.3125rem;
margin-left: -1rem;
margin-top: -0.15625rem;
}
.select2-container--bootstrap4 .select2-selection--multiple.input-lg,
.input-group-lg .select2-container--bootstrap4 .select2-selection--multiple,
.form-group-lg .select2-container--bootstrap4 .select2-selection--multiple {
min-height: calc(2.875rem + 2px);
border-radius: 0.3rem;
}
.select2-container--bootstrap4 .select2-selection--multiple.input-lg .select2-selection__choice,
.input-group-lg .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice,
.form-group-lg .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice {
font-size: 1.25rem;
line-height: 1;
border-radius: 0.25rem;
margin: 0rem 0 0 0.25rem;
padding: 0 1rem;
}
.select2-container--bootstrap4 .select2-selection--multiple.input-lg .select2-search--inline .select2-search__field,
.input-group-lg .select2-container--bootstrap4 .select2-selection--multiple .select2-search--inline .select2-search__field,
.form-group-lg .select2-container--bootstrap4 .select2-selection--multiple .select2-search--inline .select2-search__field {
padding: 0 0.5rem;
font-size: 1.25rem;
height: calc(2.875rem + 2px)-2;
line-height: 1;
}
.select2-container--bootstrap4 .select2-selection--multiple.input-lg .select2-selection__clear,
.input-group-lg .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__clear,
.form-group-lg .select2-container--bootstrap4 .select2-selection--multiple .select2-selection__clear {
margin-top: 1rem;
}
.select2-container--bootstrap4 .select2-selection.input-lg.select2-container--open .select2-selection--single .select2-selection__arrow b {
border-color: transparent transparent #6c757d transparent;
border-width: 0 0.3125rem 0.3125rem 0.3125rem;
}
.input-group-lg .select2-container--bootstrap4 .select2-selection.select2-container--open .select2-selection--single .select2-selection__arrow b {
border-color: transparent transparent #6c757d transparent;
border-width: 0 0.3125rem 0.3125rem 0.3125rem;
}
.select2-container--bootstrap4[dir="rtl"] .select2-selection--single {
padding-left: 1.125rem;
padding-right: 0.375rem;
}
.select2-container--bootstrap4[dir="rtl"] .select2-selection--single .select2-selection__rendered {
padding-right: 0;
padding-left: 0;
text-align: right;
}
.select2-container--bootstrap4[dir="rtl"] .select2-selection--single .select2-selection__clear {
float: left;
}
.select2-container--bootstrap4[dir="rtl"] .select2-selection--single .select2-selection__arrow {
left: 0.375rem;
right: auto;
}
.select2-container--bootstrap4[dir="rtl"] .select2-selection--single .select2-selection__arrow b {
margin-left: 0;
}
.select2-container--bootstrap4[dir="rtl"] .select2-selection--multiple .select2-selection__choice,
.select2-container--bootstrap4[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder,
.select2-container--bootstrap4[dir="rtl"] .select2-selection--multiple .select2-search--inline {
float: right;
}
.select2-container--bootstrap4[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
margin-left: 0;
margin-right: 0.1875rem;
}
.select2-container--bootstrap4[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
margin-left: 2px;
margin-right: auto;
}
.has-warning .select2-dropdown,
.has-warning .select2-selection {
border-color: #ffc107;
}
.has-warning .select2-container--focus .select2-selection,
.has-warning .select2-container--open .select2-selection {
border-color: #d39e00;
}
.has-warning.select2-drop-active {
border-color: #d39e00;
}
.has-warning.select2-drop-active.select2-drop.select2-drop-above {
border-top-color: #d39e00;
}
.has-error .select2-dropdown,
.has-error .select2-selection {
border-color: #dc3545;
}
.has-error .select2-container--focus .select2-selection,
.has-error .select2-container--open .select2-selection {
border-color: #bd2130;
}
.has-error.select2-drop-active {
border-color: #bd2130;
}
.has-error.select2-drop-active.select2-drop.select2-drop-above {
border-top-color: #bd2130;
}
.has-success .select2-dropdown,
.has-success .select2-selection {
border-color: #28a745;
}
.has-success .select2-container--focus .select2-selection,
.has-success .select2-container--open .select2-selection {
border-color: #1e7e34;
}
.has-success.select2-drop-active {
border-color: #1e7e34;
}
.has-success.select2-drop-active.select2-drop.select2-drop-above {
border-top-color: #1e7e34;
}
.input-group>.select2-hidden-accessible:first-child+.select2-container--bootstrap4>.selection>.select2-selection,
.input-group>.select2-hidden-accessible:first-child+.select2-container--bootstrap4>.selection>.select2-selection.form-control {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group>.select2-hidden-accessible:not(:first-child)+.select2-container--bootstrap4:not(:last-child)>.selection>.select2-selection,
.input-group>.select2-hidden-accessible:not(:first-child)+.select2-container--bootstrap4:not(:last-child)>.selection>.select2-selection.form-control {
border-radius: 0;
}
.input-group>.select2-hidden-accessible:not(:first-child):not(:last-child)+.select2-container--bootstrap4:last-child>.selection>.select2-selection,
.input-group>.select2-hidden-accessible:not(:first-child):not(:last-child)+.select2-container--bootstrap4:last-child>.selection>.select2-selection.form-control {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.input-group>.select2-container--bootstrap4 {
display: table;
table-layout: fixed;
position: relative;
z-index: 2;
width: 100%;
margin-bottom: 0;
}
.input-group>.select2-container--bootstrap4>.selection>.select2-selection.form-control {
float: none;
}
.input-group>.select2-container--bootstrap4.select2-container--open,
.input-group>.select2-container--bootstrap4.select2-container--focus {
z-index: 3;
}
.input-group>.select2-container--bootstrap4,
.input-group>.select2-container--bootstrap4 .input-group-btn,
.input-group>.select2-container--bootstrap4 .input-group-btn .btn {
vertical-align: top;
}
.form-control.select2-hidden-accessible {
position: absolute !important;
width: 1px !important;
}
@media (min-width: 576px) {
.form-inline .select2-container--bootstrap4 {
display: inline-block;
}
}
+8 -11
View File
@@ -118,12 +118,14 @@
.select2-hidden-accessible {
border: 0 !important;
clip: rect(0 0 0 0) !important;
-webkit-clip-path: inset(50%) !important;
clip-path: inset(50%) !important;
height: 1px !important;
margin: -1px !important;
overflow: hidden !important;
padding: 0 !important;
position: absolute !important;
width: 1px !important; }
width: 1px !important;
white-space: nowrap !important; }
.select2-container--default .select2-selection--single {
background-color: #fff;
@@ -186,16 +188,13 @@
width: 100%; }
.select2-container--default .select2-selection--multiple .select2-selection__rendered li {
list-style: none; }
.select2-container--default .select2-selection--multiple .select2-selection__placeholder {
color: #999;
margin-top: 5px;
float: left; }
.select2-container--default .select2-selection--multiple .select2-selection__clear {
cursor: pointer;
float: right;
font-weight: bold;
margin-top: 5px;
margin-right: 10px; }
margin-right: 10px;
padding: 1px; }
.select2-container--default .select2-selection--multiple .select2-selection__choice {
background-color: #e4e4e4;
border: 1px solid #aaa;
@@ -214,7 +213,7 @@
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
color: #333; }
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
float: right; }
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
@@ -420,9 +419,7 @@
color: #555; }
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
float: right; }
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
float: right;
margin-left: 5px;
margin-right: auto; }
+583 -220
View File
@@ -1,11 +1,11 @@
/*!
* Select2 4.0.5
* Select2 4.0.13
* https://select2.github.io
*
* Released under the MIT license
* https://github.com/select2/select2/blob/master/LICENSE.md
*/
(function (factory) {
;(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
@@ -574,10 +574,10 @@ S2.define('select2/utils',[
DecoratedClass.prototype = new ctr();
for (var m = 0; m < superMethods.length; m++) {
var superMethod = superMethods[m];
var superMethod = superMethods[m];
DecoratedClass.prototype[superMethod] =
SuperClass.prototype[superMethod];
DecoratedClass.prototype[superMethod] =
SuperClass.prototype[superMethod];
}
var calledMethod = function (methodName) {
@@ -772,6 +772,70 @@ S2.define('select2/utils',[
$element.append($nodes);
};
// Cache objects in Utils.__cache instead of $.data (see #4346)
Utils.__cache = {};
var id = 0;
Utils.GetUniqueElementId = function (element) {
// Get a unique element Id. If element has no id,
// creates a new unique number, stores it in the id
// attribute and returns the new id.
// If an id already exists, it simply returns it.
var select2Id = element.getAttribute('data-select2-id');
if (select2Id == null) {
// If element has id, use it.
if (element.id) {
select2Id = element.id;
element.setAttribute('data-select2-id', select2Id);
} else {
element.setAttribute('data-select2-id', ++id);
select2Id = id.toString();
}
}
return select2Id;
};
Utils.StoreData = function (element, name, value) {
// Stores an item in the cache for a specified element.
// name is the cache key.
var id = Utils.GetUniqueElementId(element);
if (!Utils.__cache[id]) {
Utils.__cache[id] = {};
}
Utils.__cache[id][name] = value;
};
Utils.GetData = function (element, name) {
// Retrieves a value from the cache by its key (name)
// name is optional. If no name specified, return
// all cache items for the specified element.
// and for a specified element.
var id = Utils.GetUniqueElementId(element);
if (name) {
if (Utils.__cache[id]) {
if (Utils.__cache[id][name] != null) {
return Utils.__cache[id][name];
}
return $(element).data(name); // Fallback to HTML5 data attribs.
}
return $(element).data(name); // Fallback to HTML5 data attribs.
} else {
return Utils.__cache[id];
}
};
Utils.RemoveData = function (element) {
// Removes all cached items for a specified element.
var id = Utils.GetUniqueElementId(element);
if (Utils.__cache[id] != null) {
delete Utils.__cache[id];
}
element.removeAttribute('data-select2-id');
};
return Utils;
});
@@ -791,7 +855,7 @@ S2.define('select2/results',[
Results.prototype.render = function () {
var $results = $(
'<ul class="select2-results__options" role="tree"></ul>'
'<ul class="select2-results__options" role="listbox"></ul>'
);
if (this.options.get('multiple')) {
@@ -814,7 +878,7 @@ S2.define('select2/results',[
this.hideLoading();
var $message = $(
'<li role="treeitem" aria-live="assertive"' +
'<li role="alert" aria-live="assertive"' +
' class="select2-results__option"></li>'
);
@@ -907,7 +971,7 @@ S2.define('select2/results',[
$options.each(function () {
var $option = $(this);
var item = $.data(this, 'data');
var item = Utils.GetData(this, 'data');
// id needs to be converted to a string when comparing
var id = '' + item.id;
@@ -948,11 +1012,16 @@ S2.define('select2/results',[
option.className = 'select2-results__option';
var attrs = {
'role': 'treeitem',
'role': 'option',
'aria-selected': 'false'
};
if (data.disabled) {
var matches = window.Element.prototype.matches ||
window.Element.prototype.msMatchesSelector ||
window.Element.prototype.webkitMatchesSelector;
if ((data.element != null && matches.call(data.element, ':disabled')) ||
(data.element == null && data.disabled)) {
delete attrs['aria-selected'];
attrs['aria-disabled'] = 'true';
}
@@ -1012,7 +1081,7 @@ S2.define('select2/results',[
this.template(data, option);
}
$.data(option, 'data', data);
Utils.StoreData(option, 'data', data);
return option;
};
@@ -1053,7 +1122,10 @@ S2.define('select2/results',[
}
self.setClasses();
self.highlightFirstItem();
if (self.options.get('scrollAfterSelect')) {
self.highlightFirstItem();
}
});
container.on('unselect', function () {
@@ -1062,7 +1134,10 @@ S2.define('select2/results',[
}
self.setClasses();
self.highlightFirstItem();
if (self.options.get('scrollAfterSelect')) {
self.highlightFirstItem();
}
});
container.on('open', function () {
@@ -1098,7 +1173,7 @@ S2.define('select2/results',[
return;
}
var data = $highlighted.data('data');
var data = Utils.GetData($highlighted[0], 'data');
if ($highlighted.attr('aria-selected') == 'true') {
self.trigger('close', {});
@@ -1116,8 +1191,9 @@ S2.define('select2/results',[
var currentIndex = $options.index($highlighted);
// If we are already at te top, don't move further
if (currentIndex === 0) {
// If we are already at the top, don't move further
// If no options, currentIndex will be -1
if (currentIndex <= 0) {
return;
}
@@ -1210,7 +1286,7 @@ S2.define('select2/results',[
function (evt) {
var $this = $(this);
var data = $this.data('data');
var data = Utils.GetData(this, 'data');
if ($this.attr('aria-selected') === 'true') {
if (self.options.get('multiple')) {
@@ -1233,7 +1309,7 @@ S2.define('select2/results',[
this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
function (evt) {
var data = $(this).data('data');
var data = Utils.GetData(this, 'data');
self.getHighlightedResults()
.removeClass('select2-results__option--highlighted');
@@ -1348,14 +1424,15 @@ S2.define('select2/selection/base',[
this._tabindex = 0;
if (this.$element.data('old-tabindex') != null) {
this._tabindex = this.$element.data('old-tabindex');
if (Utils.GetData(this.$element[0], 'old-tabindex') != null) {
this._tabindex = Utils.GetData(this.$element[0], 'old-tabindex');
} else if (this.$element.attr('tabindex') != null) {
this._tabindex = this.$element.attr('tabindex');
}
$selection.attr('title', this.$element.attr('title'));
$selection.attr('tabindex', this._tabindex);
$selection.attr('aria-disabled', 'false');
this.$selection = $selection;
@@ -1365,7 +1442,6 @@ S2.define('select2/selection/base',[
BaseSelection.prototype.bind = function (container, $container) {
var self = this;
var id = container.id + '-container';
var resultsId = container.id + '-results';
this.container = container;
@@ -1408,17 +1484,19 @@ S2.define('select2/selection/base',[
self.$selection.removeAttr('aria-activedescendant');
self.$selection.removeAttr('aria-owns');
self.$selection.focus();
self.$selection.trigger('focus');
self._detachCloseHandler(container);
});
container.on('enable', function () {
self.$selection.attr('tabindex', self._tabindex);
self.$selection.attr('aria-disabled', 'false');
});
container.on('disable', function () {
self.$selection.attr('tabindex', '-1');
self.$selection.attr('aria-disabled', 'true');
});
};
@@ -1441,7 +1519,6 @@ S2.define('select2/selection/base',[
};
BaseSelection.prototype._attachCloseHandler = function (container) {
var self = this;
$(document.body).on('mousedown.select2.' + container.id, function (e) {
var $target = $(e.target);
@@ -1451,13 +1528,11 @@ S2.define('select2/selection/base',[
var $all = $('.select2.select2-container--open');
$all.each(function () {
var $this = $(this);
if (this == $select[0]) {
return;
}
var $element = $this.data('element');
var $element = Utils.GetData(this, 'element');
$element.select2('close');
});
@@ -1481,6 +1556,27 @@ S2.define('select2/selection/base',[
throw new Error('The `update` method must be defined in child classes.');
};
/**
* Helper method to abstract the "enabled" (not "disabled") state of this
* object.
*
* @return {true} if the instance is not disabled.
* @return {false} if the instance is disabled.
*/
BaseSelection.prototype.isEnabled = function () {
return !this.isDisabled();
};
/**
* Helper method to abstract the "disabled" state of this object.
*
* @return {true} if the disabled option is true.
* @return {false} if the disabled option is false.
*/
BaseSelection.prototype.isDisabled = function () {
return this.options.get('disabled');
};
return BaseSelection;
});
@@ -1518,7 +1614,10 @@ S2.define('select2/selection/single',[
var id = container.id + '-container';
this.$selection.find('.select2-selection__rendered').attr('id', id);
this.$selection.find('.select2-selection__rendered')
.attr('id', id)
.attr('role', 'textbox')
.attr('aria-readonly', 'true');
this.$selection.attr('aria-labelledby', id);
this.$selection.on('mousedown', function (evt) {
@@ -1542,17 +1641,15 @@ S2.define('select2/selection/single',[
container.on('focus', function (evt) {
if (!container.isOpen()) {
self.$selection.focus();
self.$selection.trigger('focus');
}
});
container.on('selection:update', function (params) {
self.update(params.data);
});
};
SingleSelection.prototype.clear = function () {
this.$selection.find('.select2-selection__rendered').empty();
var $rendered = this.$selection.find('.select2-selection__rendered');
$rendered.empty();
$rendered.removeAttr('title'); // clear tooltip on empty
};
SingleSelection.prototype.display = function (data, container) {
@@ -1578,7 +1675,14 @@ S2.define('select2/selection/single',[
var formatted = this.display(selection, $rendered);
$rendered.empty().append(formatted);
$rendered.prop('title', selection.title || selection.text);
var title = selection.title || selection.text;
if (title) {
$rendered.attr('title', title);
} else {
$rendered.removeAttr('title');
}
};
return SingleSelection;
@@ -1623,14 +1727,14 @@ S2.define('select2/selection/multiple',[
'.select2-selection__choice__remove',
function (evt) {
// Ignore the event if it is disabled
if (self.options.get('disabled')) {
if (self.isDisabled()) {
return;
}
var $remove = $(this);
var $selection = $remove.parent();
var data = $selection.data('data');
var data = Utils.GetData($selection[0], 'data');
self.trigger('unselect', {
originalEvent: evt,
@@ -1641,7 +1745,9 @@ S2.define('select2/selection/multiple',[
};
MultipleSelection.prototype.clear = function () {
this.$selection.find('.select2-selection__rendered').empty();
var $rendered = this.$selection.find('.select2-selection__rendered');
$rendered.empty();
$rendered.removeAttr('title');
};
MultipleSelection.prototype.display = function (data, container) {
@@ -1679,9 +1785,14 @@ S2.define('select2/selection/multiple',[
var formatted = this.display(selection, $selection);
$selection.append(formatted);
$selection.prop('title', selection.title || selection.text);
$selection.data('data', selection);
var title = selection.title || selection.text;
if (title) {
$selection.attr('title', title);
}
Utils.StoreData($selection[0], 'data', selection);
$selections.push($selection);
}
@@ -1746,8 +1857,9 @@ S2.define('select2/selection/placeholder',[
S2.define('select2/selection/allowClear',[
'jquery',
'../keys'
], function ($, KEYS) {
'../keys',
'../utils'
], function ($, KEYS, Utils) {
function AllowClear () { }
AllowClear.prototype.bind = function (decorated, container, $container) {
@@ -1776,7 +1888,7 @@ S2.define('select2/selection/allowClear',[
AllowClear.prototype._handleClear = function (_, evt) {
// Ignore the event if it is disabled
if (this.options.get('disabled')) {
if (this.isDisabled()) {
return;
}
@@ -1789,10 +1901,22 @@ S2.define('select2/selection/allowClear',[
evt.stopPropagation();
var data = $clear.data('data');
var data = Utils.GetData($clear[0], 'data');
var previousVal = this.$element.val();
this.$element.val(this.placeholder.id);
var unselectData = {
data: data
};
this.trigger('clear', unselectData);
if (unselectData.prevented) {
this.$element.val(previousVal);
return;
}
for (var d = 0; d < data.length; d++) {
var unselectData = {
unselectData = {
data: data[d]
};
@@ -1802,11 +1926,12 @@ S2.define('select2/selection/allowClear',[
// If the event was prevented, don't clear it out.
if (unselectData.prevented) {
this.$element.val(previousVal);
return;
}
}
this.$element.val(this.placeholder.id).trigger('change');
this.$element.trigger('input').trigger('change');
this.trigger('toggle', {});
};
@@ -1829,12 +1954,14 @@ S2.define('select2/selection/allowClear',[
return;
}
var removeAll = this.options.get('translations').get('removeAllItems');
var $remove = $(
'<span class="select2-selection__clear">' +
'<span class="select2-selection__clear" title="' + removeAll() +'">' +
'&times;' +
'</span>'
);
$remove.data('data', data);
Utils.StoreData($remove[0], 'data', data);
this.$selection.find('.select2-selection__rendered').prepend($remove);
};
@@ -1856,7 +1983,7 @@ S2.define('select2/selection/search',[
'<li class="select2-search select2-search--inline">' +
'<input class="select2-search__field" type="search" tabindex="-1"' +
' autocomplete="off" autocorrect="off" autocapitalize="none"' +
' spellcheck="false" role="textbox" aria-autocomplete="list" />' +
' spellcheck="false" role="searchbox" aria-autocomplete="list" />' +
'</li>'
);
@@ -1873,14 +2000,18 @@ S2.define('select2/selection/search',[
Search.prototype.bind = function (decorated, container, $container) {
var self = this;
var resultsId = container.id + '-results';
decorated.call(this, container, $container);
container.on('open', function () {
self.$search.attr('aria-controls', resultsId);
self.$search.trigger('focus');
});
container.on('close', function () {
self.$search.val('');
self.$search.removeAttr('aria-controls');
self.$search.removeAttr('aria-activedescendant');
self.$search.trigger('focus');
});
@@ -1900,7 +2031,11 @@ S2.define('select2/selection/search',[
});
container.on('results:focus', function (params) {
self.$search.attr('aria-activedescendant', params.id);
if (params.data._resultId) {
self.$search.attr('aria-activedescendant', params.data._resultId);
} else {
self.$search.removeAttr('aria-activedescendant');
}
});
this.$selection.on('focusin', '.select2-search--inline', function (evt) {
@@ -1925,7 +2060,7 @@ S2.define('select2/selection/search',[
.prev('.select2-selection__choice');
if ($previousChoice.length > 0) {
var item = $previousChoice.data('data');
var item = Utils.GetData($previousChoice[0], 'data');
self.searchRemoveChoice(item);
@@ -1934,6 +2069,12 @@ S2.define('select2/selection/search',[
}
});
this.$selection.on('click', '.select2-search--inline', function (evt) {
if (self.$search.val()) {
evt.stopPropagation();
}
});
// Try to detect the IE version should the `documentMode` property that
// is stored on the document. This is only implemented in IE and is
// slightly cleaner than doing a user agent check.
@@ -2019,7 +2160,7 @@ S2.define('select2/selection/search',[
this.resizeSearch();
if (searchHadFocus) {
this.$search.focus();
this.$search.trigger('focus');
}
};
@@ -2052,7 +2193,7 @@ S2.define('select2/selection/search',[
var width = '';
if (this.$search.attr('placeholder') !== '') {
width = this.$selection.find('.select2-selection__rendered').innerWidth();
width = this.$selection.find('.select2-selection__rendered').width();
} else {
var minimumWidth = this.$search.val().length + 1;
@@ -2076,10 +2217,13 @@ S2.define('select2/selection/eventRelay',[
'open', 'opening',
'close', 'closing',
'select', 'selecting',
'unselect', 'unselecting'
'unselect', 'unselecting',
'clear', 'clearing'
];
var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting'];
var preventableEvents = [
'opening', 'closing', 'selecting', 'unselecting', 'clearing'
];
decorated.call(this, container, $container);
@@ -2412,6 +2556,7 @@ S2.define('select2/diacritics',[
'\u019F': 'O',
'\uA74A': 'O',
'\uA74C': 'O',
'\u0152': 'OE',
'\u01A2': 'OI',
'\uA74E': 'OO',
'\u0222': 'OU',
@@ -2821,6 +2966,7 @@ S2.define('select2/diacritics',[
'\uA74B': 'o',
'\uA74D': 'o',
'\u0275': 'o',
'\u0153': 'oe',
'\u01A3': 'oi',
'\u0223': 'ou',
'\uA74F': 'oo',
@@ -2989,8 +3135,9 @@ S2.define('select2/diacritics',[
'\u03CD': '\u03C5',
'\u03CB': '\u03C5',
'\u03B0': '\u03C5',
'\u03C9': '\u03C9',
'\u03C2': '\u03C3'
'\u03CE': '\u03C9',
'\u03C2': '\u03C3',
'\u2019': '\''
};
return diacritics;
@@ -3075,7 +3222,7 @@ S2.define('select2/data/select',[
if ($(data.element).is('option')) {
data.element.selected = true;
this.$element.trigger('change');
this.$element.trigger('input').trigger('change');
return;
}
@@ -3096,13 +3243,13 @@ S2.define('select2/data/select',[
}
self.$element.val(val);
self.$element.trigger('change');
self.$element.trigger('input').trigger('change');
});
} else {
var val = data.id;
this.$element.val(val);
this.$element.trigger('change');
this.$element.trigger('input').trigger('change');
}
};
@@ -3118,7 +3265,7 @@ S2.define('select2/data/select',[
if ($(data.element).is('option')) {
data.element.selected = false;
this.$element.trigger('change');
this.$element.trigger('input').trigger('change');
return;
}
@@ -3136,7 +3283,7 @@ S2.define('select2/data/select',[
self.$element.val(val);
self.$element.trigger('change');
self.$element.trigger('input').trigger('change');
});
};
@@ -3158,7 +3305,7 @@ S2.define('select2/data/select',[
// Remove anything added to child elements
this.$element.find('*').each(function () {
// Remove any custom data set by Select2
$.removeData(this, 'data');
Utils.RemoveData(this);
});
};
@@ -3231,7 +3378,7 @@ S2.define('select2/data/select',[
normalizedData.element = option;
// Override the option's data with the combined data
$.data(option, 'data', normalizedData);
Utils.StoreData(option, 'data', normalizedData);
return $option;
};
@@ -3239,7 +3386,7 @@ S2.define('select2/data/select',[
SelectAdapter.prototype.item = function ($option) {
var data = {};
data = $.data($option[0], 'data');
data = Utils.GetData($option[0], 'data');
if (data != null) {
return data;
@@ -3277,13 +3424,13 @@ S2.define('select2/data/select',[
data = this._normalizeItem(data);
data.element = $option[0];
$.data($option[0], 'data', data);
Utils.StoreData($option[0], 'data', data);
return data;
};
SelectAdapter.prototype._normalizeItem = function (item) {
if (!$.isPlainObject(item)) {
if (item !== Object(item)) {
item = {
id: item,
text: item
@@ -3329,15 +3476,19 @@ S2.define('select2/data/array',[
'jquery'
], function (SelectAdapter, Utils, $) {
function ArrayAdapter ($element, options) {
var data = options.get('data') || [];
this._dataToConvert = options.get('data') || [];
ArrayAdapter.__super__.constructor.call(this, $element, options);
this.addOptions(this.convertToOptions(data));
}
Utils.Extend(ArrayAdapter, SelectAdapter);
ArrayAdapter.prototype.bind = function (container, $container) {
ArrayAdapter.__super__.bind.call(this, container, $container);
this.addOptions(this.convertToOptions(this._dataToConvert));
};
ArrayAdapter.prototype.select = function (data) {
var $option = this.$element.find('option').filter(function (i, elm) {
return elm.value == data.id.toString();
@@ -3487,7 +3638,8 @@ S2.define('select2/data/ajax',[
}, function () {
// Attempt to detect if a request was aborted
// Only works if the transport exposes a status property
if ($request.status && $request.status === '0') {
if ('status' in $request &&
($request.status === 0 || $request.status === '0')) {
return;
}
@@ -3626,8 +3778,6 @@ S2.define('select2/data/tags',[
};
Tags.prototype._removeOldTags = function (_) {
var tag = this._lastTag;
var $options = this.$element.find('option[data-select2-tag]');
$options.each(function () {
@@ -3702,7 +3852,7 @@ S2.define('select2/data/tokenizer',[
// Replace the search term if we have the search box
if (this.$search.length) {
this.$search.val(tokenData.term);
this.$search.focus();
this.$search.trigger('focus');
}
params.term = tokenData.term;
@@ -3831,10 +3981,30 @@ S2.define('select2/data/maximumSelectionLength',[
decorated.call(this, $e, options);
}
MaximumSelectionLength.prototype.bind =
function (decorated, container, $container) {
var self = this;
decorated.call(this, container, $container);
container.on('select', function () {
self._checkIfMaximumSelected();
});
};
MaximumSelectionLength.prototype.query =
function (decorated, params, callback) {
var self = this;
this._checkIfMaximumSelected(function () {
decorated.call(self, params, callback);
});
};
MaximumSelectionLength.prototype._checkIfMaximumSelected =
function (_, successCallback) {
var self = this;
this.current(function (currentData) {
var count = currentData != null ? currentData.length : 0;
if (self.maximumSelectionLength > 0 &&
@@ -3847,7 +4017,10 @@ S2.define('select2/data/maximumSelectionLength',[
});
return;
}
decorated.call(self, params, callback);
if (successCallback) {
successCallback();
}
});
};
@@ -3886,7 +4059,7 @@ S2.define('select2/dropdown',[
};
Dropdown.prototype.position = function ($dropdown, $container) {
// Should be implmented in subclasses
// Should be implemented in subclasses
};
Dropdown.prototype.destroy = function () {
@@ -3910,7 +4083,7 @@ S2.define('select2/dropdown/search',[
'<span class="select2-search select2-search--dropdown">' +
'<input class="select2-search__field" type="search" tabindex="-1"' +
' autocomplete="off" autocorrect="off" autocapitalize="none"' +
' spellcheck="false" role="textbox" />' +
' spellcheck="false" role="searchbox" aria-autocomplete="list" />' +
'</span>'
);
@@ -3925,6 +4098,8 @@ S2.define('select2/dropdown/search',[
Search.prototype.bind = function (decorated, container, $container) {
var self = this;
var resultsId = container.id + '-results';
decorated.call(this, container, $container);
this.$search.on('keydown', function (evt) {
@@ -3947,23 +4122,27 @@ S2.define('select2/dropdown/search',[
container.on('open', function () {
self.$search.attr('tabindex', 0);
self.$search.attr('aria-controls', resultsId);
self.$search.focus();
self.$search.trigger('focus');
window.setTimeout(function () {
self.$search.focus();
self.$search.trigger('focus');
}, 0);
});
container.on('close', function () {
self.$search.attr('tabindex', -1);
self.$search.removeAttr('aria-controls');
self.$search.removeAttr('aria-activedescendant');
self.$search.val('');
self.$search.trigger('blur');
});
container.on('focus', function () {
if (!container.isOpen()) {
self.$search.focus();
self.$search.trigger('focus');
}
});
@@ -3978,6 +4157,14 @@ S2.define('select2/dropdown/search',[
}
}
});
container.on('results:focus', function (params) {
if (params.data._resultId) {
self.$search.attr('aria-activedescendant', params.data._resultId);
} else {
self.$search.removeAttr('aria-activedescendant');
}
});
};
Search.prototype.handleSearch = function (evt) {
@@ -4062,6 +4249,7 @@ S2.define('select2/dropdown/infiniteScroll',[
if (this.showLoadingMore(data)) {
this.$results.append(this.$loadingMore);
this.loadMoreIfNeeded();
}
};
@@ -4080,25 +4268,27 @@ S2.define('select2/dropdown/infiniteScroll',[
self.loading = true;
});
this.$results.on('scroll', function () {
var isLoadMoreVisible = $.contains(
document.documentElement,
self.$loadingMore[0]
);
this.$results.on('scroll', this.loadMoreIfNeeded.bind(this));
};
if (self.loading || !isLoadMoreVisible) {
return;
}
InfiniteScroll.prototype.loadMoreIfNeeded = function () {
var isLoadMoreVisible = $.contains(
document.documentElement,
this.$loadingMore[0]
);
var currentOffset = self.$results.offset().top +
self.$results.outerHeight(false);
var loadingMoreOffset = self.$loadingMore.offset().top +
self.$loadingMore.outerHeight(false);
if (this.loading || !isLoadMoreVisible) {
return;
}
if (currentOffset + 50 >= loadingMoreOffset) {
self.loadMore();
}
});
var currentOffset = this.$results.offset().top +
this.$results.outerHeight(false);
var loadingMoreOffset = this.$loadingMore.offset().top +
this.$loadingMore.outerHeight(false);
if (currentOffset + 50 >= loadingMoreOffset) {
this.loadMore();
}
};
InfiniteScroll.prototype.loadMore = function () {
@@ -4119,7 +4309,7 @@ S2.define('select2/dropdown/infiniteScroll',[
var $option = $(
'<li ' +
'class="select2-results__option select2-results__option--load-more"' +
'role="treeitem" aria-disabled="true"></li>'
'role="option" aria-disabled="true"></li>'
);
var message = this.options.get('translations').get('loadingMore');
@@ -4137,7 +4327,7 @@ S2.define('select2/dropdown/attachBody',[
'../utils'
], function ($, Utils) {
function AttachBody (decorated, $element, options) {
this.$dropdownParent = options.get('dropdownParent') || $(document.body);
this.$dropdownParent = $(options.get('dropdownParent') || document.body);
decorated.call(this, $element, options);
}
@@ -4145,27 +4335,14 @@ S2.define('select2/dropdown/attachBody',[
AttachBody.prototype.bind = function (decorated, container, $container) {
var self = this;
var setupResultsEvents = false;
decorated.call(this, container, $container);
container.on('open', function () {
self._showDropdown();
self._attachPositioningHandler(container);
if (!setupResultsEvents) {
setupResultsEvents = true;
container.on('results:all', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('results:append', function () {
self._positionDropdown();
self._resizeDropdown();
});
}
// Must bind after the results handlers to ensure correct sizing
self._bindContainerResultHandlers(container);
});
container.on('close', function () {
@@ -4214,6 +4391,44 @@ S2.define('select2/dropdown/attachBody',[
this.$dropdownContainer.detach();
};
AttachBody.prototype._bindContainerResultHandlers =
function (decorated, container) {
// These should only be bound once
if (this._containerResultsHandlersBound) {
return;
}
var self = this;
container.on('results:all', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('results:append', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('results:message', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('select', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('unselect', function () {
self._positionDropdown();
self._resizeDropdown();
});
this._containerResultsHandlersBound = true;
};
AttachBody.prototype._attachPositioningHandler =
function (decorated, container) {
var self = this;
@@ -4224,14 +4439,14 @@ S2.define('select2/dropdown/attachBody',[
var $watchers = this.$container.parents().filter(Utils.hasScroll);
$watchers.each(function () {
$(this).data('select2-scroll-position', {
Utils.StoreData(this, 'select2-scroll-position', {
x: $(this).scrollLeft(),
y: $(this).scrollTop()
});
});
$watchers.on(scrollEvent, function (ev) {
var position = $(this).data('select2-scroll-position');
var position = Utils.GetData(this, 'select2-scroll-position');
$(this).scrollTop(position.y);
});
@@ -4290,16 +4505,26 @@ S2.define('select2/dropdown/attachBody',[
top: container.bottom
};
// Determine what the parent element is to use for calciulating the offset
// Determine what the parent element is to use for calculating the offset
var $offsetParent = this.$dropdownParent;
// For statically positoned elements, we need to get the element
// For statically positioned elements, we need to get the element
// that is determining the offset
if ($offsetParent.css('position') === 'static') {
$offsetParent = $offsetParent.offsetParent();
}
var parentOffset = $offsetParent.offset();
var parentOffset = {
top: 0,
left: 0
};
if (
$.contains(document.body, $offsetParent[0]) ||
$offsetParent[0].isConnected
) {
parentOffset = $offsetParent.offset();
}
css.top -= parentOffset.top;
css.left -= parentOffset.left;
@@ -4396,8 +4621,8 @@ S2.define('select2/dropdown/minimumResultsForSearch',[
});
S2.define('select2/dropdown/selectOnClose',[
], function () {
'../utils'
], function (Utils) {
function SelectOnClose () { }
SelectOnClose.prototype.bind = function (decorated, container, $container) {
@@ -4428,7 +4653,7 @@ S2.define('select2/dropdown/selectOnClose',[
return;
}
var data = $highlightedResults.data('data');
var data = Utils.GetData($highlightedResults[0], 'data');
// Don't re-select already selected resulte
if (
@@ -4469,7 +4694,7 @@ S2.define('select2/dropdown/closeOnSelect',[
var originalEvent = evt.originalEvent;
// Don't close if the control key is being held
if (originalEvent && originalEvent.ctrlKey) {
if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) {
return;
}
@@ -4523,6 +4748,9 @@ S2.define('select2/i18n/en',[],function () {
},
searching: function () {
return 'Searching…';
},
removeAllItems: function () {
return 'Remove all items';
}
};
});
@@ -4761,66 +4989,29 @@ S2.define('select2/defaults',[
);
}
if (typeof options.language === 'string') {
// Check if the language is specified with a region
if (options.language.indexOf('-') > 0) {
// Extract the region information if it is included
var languageParts = options.language.split('-');
var baseLanguage = languageParts[0];
// If the defaults were not previously applied from an element, it is
// possible for the language option to have not been resolved
options.language = this._resolveLanguage(options.language);
options.language = [options.language, baseLanguage];
} else {
options.language = [options.language];
// Always fall back to English since it will always be complete
options.language.push('en');
var uniqueLanguages = [];
for (var l = 0; l < options.language.length; l++) {
var language = options.language[l];
if (uniqueLanguages.indexOf(language) === -1) {
uniqueLanguages.push(language);
}
}
if ($.isArray(options.language)) {
var languages = new Translation();
options.language.push('en');
options.language = uniqueLanguages;
var languageNames = options.language;
for (var l = 0; l < languageNames.length; l++) {
var name = languageNames[l];
var language = {};
try {
// Try to load it with the original name
language = Translation.loadPath(name);
} catch (e) {
try {
// If we couldn't load it, check if it wasn't the full path
name = this.defaults.amdLanguageBase + name;
language = Translation.loadPath(name);
} catch (ex) {
// The translation could not be loaded at all. Sometimes this is
// because of a configuration problem, other times this can be
// because of how Select2 helps load all possible translation files.
if (options.debug && window.console && console.warn) {
console.warn(
'Select2: The language file for "' + name + '" could not be ' +
'automatically loaded. A fallback will be used instead.'
);
}
continue;
}
}
languages.extend(language);
}
options.translations = languages;
} else {
var baseTranslation = Translation.loadPath(
this.defaults.amdLanguageBase + 'en'
);
var customTranslation = new Translation(options.language);
customTranslation.extend(baseTranslation);
options.translations = customTranslation;
}
options.translations = this._processTranslations(
options.language,
options.debug
);
return options;
};
@@ -4887,13 +5078,14 @@ S2.define('select2/defaults',[
debug: false,
dropdownAutoWidth: false,
escapeMarkup: Utils.escapeMarkup,
language: EnglishTranslation,
language: {},
matcher: matcher,
minimumInputLength: 0,
maximumInputLength: 0,
maximumSelectionLength: 0,
minimumResultsForSearch: 0,
selectOnClose: false,
scrollAfterSelect: false,
sorter: function (data) {
return data;
},
@@ -4908,6 +5100,103 @@ S2.define('select2/defaults',[
};
};
Defaults.prototype.applyFromElement = function (options, $element) {
var optionLanguage = options.language;
var defaultLanguage = this.defaults.language;
var elementLanguage = $element.prop('lang');
var parentLanguage = $element.closest('[lang]').prop('lang');
var languages = Array.prototype.concat.call(
this._resolveLanguage(elementLanguage),
this._resolveLanguage(optionLanguage),
this._resolveLanguage(defaultLanguage),
this._resolveLanguage(parentLanguage)
);
options.language = languages;
return options;
};
Defaults.prototype._resolveLanguage = function (language) {
if (!language) {
return [];
}
if ($.isEmptyObject(language)) {
return [];
}
if ($.isPlainObject(language)) {
return [language];
}
var languages;
if (!$.isArray(language)) {
languages = [language];
} else {
languages = language;
}
var resolvedLanguages = [];
for (var l = 0; l < languages.length; l++) {
resolvedLanguages.push(languages[l]);
if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) {
// Extract the region information if it is included
var languageParts = languages[l].split('-');
var baseLanguage = languageParts[0];
resolvedLanguages.push(baseLanguage);
}
}
return resolvedLanguages;
};
Defaults.prototype._processTranslations = function (languages, debug) {
var translations = new Translation();
for (var l = 0; l < languages.length; l++) {
var languageData = new Translation();
var language = languages[l];
if (typeof language === 'string') {
try {
// Try to load it with the original name
languageData = Translation.loadPath(language);
} catch (e) {
try {
// If we couldn't load it, check if it wasn't the full path
language = this.defaults.amdLanguageBase + language;
languageData = Translation.loadPath(language);
} catch (ex) {
// The translation could not be loaded at all. Sometimes this is
// because of a configuration problem, other times this can be
// because of how Select2 helps load all possible translation files
if (debug && window.console && console.warn) {
console.warn(
'Select2: The language file for "' + language + '" could ' +
'not be automatically loaded. A fallback will be used instead.'
);
}
}
}
} else if ($.isPlainObject(language)) {
languageData = new Translation(language);
} else {
languageData = language;
}
translations.extend(languageData);
}
return translations;
};
Defaults.prototype.set = function (key, value) {
var camelKey = $.camelCase(key);
@@ -4916,7 +5205,7 @@ S2.define('select2/defaults',[
var convertedData = Utils._convertData(data);
$.extend(this.defaults, convertedData);
$.extend(true, this.defaults, convertedData);
};
var defaults = new Defaults();
@@ -4937,6 +5226,10 @@ S2.define('select2/options',[
this.fromElement($element);
}
if ($element != null) {
this.options = Defaults.applyFromElement(this.options, $element);
}
this.options = Defaults.apply(this.options);
if ($element && $element.is('input')) {
@@ -4960,14 +5253,6 @@ S2.define('select2/options',[
this.options.disabled = $e.prop('disabled');
}
if (this.options.language == null) {
if ($e.prop('lang')) {
this.options.language = $e.prop('lang').toLowerCase();
} else if ($e.closest('[lang]').prop('lang')) {
this.options.language = $e.closest('[lang]').prop('lang');
}
}
if (this.options.dir == null) {
if ($e.prop('dir')) {
this.options.dir = $e.prop('dir');
@@ -4981,7 +5266,7 @@ S2.define('select2/options',[
$e.prop('disabled', this.options.disabled);
$e.prop('multiple', this.options.multiple);
if ($e.data('select2Tags')) {
if (Utils.GetData($e[0], 'select2Tags')) {
if (this.options.debug && window.console && console.warn) {
console.warn(
'Select2: The `data-select2-tags` attribute has been changed to ' +
@@ -4990,11 +5275,11 @@ S2.define('select2/options',[
);
}
$e.data('data', $e.data('select2Tags'));
$e.data('tags', true);
Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags'));
Utils.StoreData($e[0], 'tags', true);
}
if ($e.data('ajaxUrl')) {
if (Utils.GetData($e[0], 'ajaxUrl')) {
if (this.options.debug && window.console && console.warn) {
console.warn(
'Select2: The `data-ajax-url` attribute has been changed to ' +
@@ -5003,21 +5288,45 @@ S2.define('select2/options',[
);
}
$e.attr('ajax--url', $e.data('ajaxUrl'));
$e.data('ajax--url', $e.data('ajaxUrl'));
$e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl'));
Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl'));
}
var dataset = {};
function upperCaseLetter(_, letter) {
return letter.toUpperCase();
}
// Pre-load all of the attributes which are prefixed with `data-`
for (var attr = 0; attr < $e[0].attributes.length; attr++) {
var attributeName = $e[0].attributes[attr].name;
var prefix = 'data-';
if (attributeName.substr(0, prefix.length) == prefix) {
// Get the contents of the attribute after `data-`
var dataName = attributeName.substring(prefix.length);
// Get the data contents from the consistent source
// This is more than likely the jQuery data helper
var dataValue = Utils.GetData($e[0], dataName);
// camelCase the attribute name to match the spec
var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter);
// Store the data attribute contents into the dataset since
dataset[camelDataName] = dataValue;
}
}
// Prefer the element's `dataset` attribute if it exists
// jQuery 1.x does not correctly handle data attributes with multiple dashes
if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) {
dataset = $.extend(true, {}, $e[0].dataset, $e.data());
} else {
dataset = $e.data();
dataset = $.extend(true, {}, $e[0].dataset, dataset);
}
var data = $.extend(true, {}, dataset);
// Prefer our internal data cache if it exists
var data = $.extend(true, {}, Utils.GetData($e[0]), dataset);
data = Utils._convertData(data);
@@ -5054,8 +5363,8 @@ S2.define('select2/core',[
'./keys'
], function ($, Options, Utils, KEYS) {
var Select2 = function ($element, options) {
if ($element.data('select2') != null) {
$element.data('select2').destroy();
if (Utils.GetData($element[0], 'select2') != null) {
Utils.GetData($element[0], 'select2').destroy();
}
this.$element = $element;
@@ -5071,7 +5380,7 @@ S2.define('select2/core',[
// Set up the tabindex
var tabindex = $element.attr('tabindex') || 0;
$element.data('old-tabindex', tabindex);
Utils.StoreData($element[0], 'old-tabindex', tabindex);
$element.attr('tabindex', '-1');
// Set up containers and adapters
@@ -5132,6 +5441,9 @@ S2.define('select2/core',[
// Synchronize any monitored attributes
this._syncAttributes();
Utils.StoreData($element[0], 'select2', this);
// Ensure backwards compatibility with $element.data('select2').
$element.data('select2', this);
};
@@ -5208,6 +5520,12 @@ S2.define('select2/core',[
return null;
}
if (method == 'computedstyle') {
var computedStyle = window.getComputedStyle($element[0]);
return computedStyle.width;
}
return method;
};
@@ -5248,8 +5566,8 @@ S2.define('select2/core',[
if (observer != null) {
this._observer = new observer(function (mutations) {
$.each(mutations, self._syncA);
$.each(mutations, self._syncS);
self._syncA();
self._syncS(null, mutations);
});
this._observer.observe(this.$element[0], {
attributes: true,
@@ -5371,7 +5689,7 @@ S2.define('select2/core',[
if (self.isOpen()) {
if (key === KEYS.ESC || key === KEYS.TAB ||
(key === KEYS.UP && evt.altKey)) {
self.close();
self.close(evt);
evt.preventDefault();
} else if (key === KEYS.ENTER) {
@@ -5405,7 +5723,7 @@ S2.define('select2/core',[
Select2.prototype._syncAttributes = function () {
this.options.set('disabled', this.$element.prop('disabled'));
if (this.options.get('disabled')) {
if (this.isDisabled()) {
if (this.isOpen()) {
this.close();
}
@@ -5416,7 +5734,7 @@ S2.define('select2/core',[
}
};
Select2.prototype._syncSubtree = function (evt, mutations) {
Select2.prototype._isChangeMutation = function (evt, mutations) {
var changed = false;
var self = this;
@@ -5444,7 +5762,22 @@ S2.define('select2/core',[
}
} else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
changed = true;
} else if ($.isArray(mutations)) {
$.each(mutations, function(evt, mutation) {
if (self._isChangeMutation(evt, mutation)) {
// We've found a change mutation.
// Let's escape from the loop and continue
changed = true;
return false;
}
});
}
return changed;
};
Select2.prototype._syncSubtree = function (evt, mutations) {
var changed = this._isChangeMutation(evt, mutations);
var self = this;
// Only re-pull the data if we think there is a change
if (changed) {
@@ -5466,7 +5799,8 @@ S2.define('select2/core',[
'open': 'opening',
'close': 'closing',
'select': 'selecting',
'unselect': 'unselecting'
'unselect': 'unselecting',
'clear': 'clearing'
};
if (args === undefined) {
@@ -5494,7 +5828,7 @@ S2.define('select2/core',[
};
Select2.prototype.toggleDropdown = function () {
if (this.options.get('disabled')) {
if (this.isDisabled()) {
return;
}
@@ -5510,15 +5844,40 @@ S2.define('select2/core',[
return;
}
if (this.isDisabled()) {
return;
}
this.trigger('query', {});
};
Select2.prototype.close = function () {
Select2.prototype.close = function (evt) {
if (!this.isOpen()) {
return;
}
this.trigger('close', {});
this.trigger('close', { originalEvent : evt });
};
/**
* Helper method to abstract the "enabled" (not "disabled") state of this
* object.
*
* @return {true} if the instance is not disabled.
* @return {false} if the instance is disabled.
*/
Select2.prototype.isEnabled = function () {
return !this.isDisabled();
};
/**
* Helper method to abstract the "disabled" state of this object.
*
* @return {true} if the disabled option is true.
* @return {false} if the disabled option is false.
*/
Select2.prototype.isDisabled = function () {
return this.options.get('disabled');
};
Select2.prototype.isOpen = function () {
@@ -5595,7 +5954,7 @@ S2.define('select2/core',[
});
}
this.$element.val(newVal).trigger('change');
this.$element.val(newVal).trigger('input').trigger('change');
};
Select2.prototype.destroy = function () {
@@ -5621,10 +5980,12 @@ S2.define('select2/core',[
this._syncS = null;
this.$element.off('.select2');
this.$element.attr('tabindex', this.$element.data('old-tabindex'));
this.$element.attr('tabindex',
Utils.GetData(this.$element[0], 'old-tabindex'));
this.$element.removeClass('select2-hidden-accessible');
this.$element.attr('aria-hidden', 'false');
Utils.RemoveData(this.$element[0]);
this.$element.removeData('select2');
this.dataAdapter.destroy();
@@ -5652,7 +6013,7 @@ S2.define('select2/core',[
this.$container.addClass('select2-container--' + this.options.get('theme'));
$container.data('element', this.$element);
Utils.StoreData($container[0], 'element', this.$element);
return $container;
};
@@ -5862,8 +6223,9 @@ S2.define('select2/compat/initSelection',[
});
S2.define('select2/compat/inputData',[
'jquery'
], function ($) {
'jquery',
'../utils'
], function ($, Utils) {
function InputData (decorated, $element, options) {
this._currentData = [];
this._valueSeparator = options.get('valueSeparator') || ',';
@@ -5927,13 +6289,13 @@ S2.define('select2/compat/inputData',[
});
this.$element.val(data.id);
this.$element.trigger('change');
this.$element.trigger('input').trigger('change');
} else {
var value = this.$element.val();
value += this._valueSeparator + data.id;
this.$element.val(value);
this.$element.trigger('change');
this.$element.trigger('input').trigger('change');
}
};
@@ -5956,7 +6318,7 @@ S2.define('select2/compat/inputData',[
}
self.$element.val(values.join(self._valueSeparator));
self.$element.trigger('change');
self.$element.trigger('input').trigger('change');
});
};
@@ -5980,7 +6342,7 @@ S2.define('select2/compat/inputData',[
InputData.prototype.addOptions = function (_, $options) {
var options = $.map($options, function ($option) {
return $.data($option[0], 'data');
return Utils.GetData($option[0], 'data');
});
this._currentData.push.apply(this._currentData, options);
@@ -6383,8 +6745,9 @@ S2.define('jquery.select2',[
'jquery-mousewheel',
'./select2/core',
'./select2/defaults'
], function ($, _, Select2, Defaults) {
'./select2/defaults',
'./select2/utils'
], function ($, _, Select2, Defaults, Utils) {
if ($.fn.select2 == null) {
// All methods that should return the element
var thisMethods = ['open', 'close', 'destroy'];
@@ -6405,7 +6768,7 @@ S2.define('jquery.select2',[
var args = Array.prototype.slice.call(arguments, 1);
this.each(function () {
var instance = $(this).data('select2');
var instance = Utils.GetData(this, 'select2');
if (instance == null && window.console && console.error) {
console.error(
+2 -1
View File
File diff suppressed because one or more lines are too long
+576 -214
View File
@@ -1,11 +1,11 @@
/*!
* Select2 4.0.5
* Select2 4.0.13
* https://select2.github.io
*
* Released under the MIT license
* https://github.com/select2/select2/blob/master/LICENSE.md
*/
(function (factory) {
;(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
@@ -574,10 +574,10 @@ S2.define('select2/utils',[
DecoratedClass.prototype = new ctr();
for (var m = 0; m < superMethods.length; m++) {
var superMethod = superMethods[m];
var superMethod = superMethods[m];
DecoratedClass.prototype[superMethod] =
SuperClass.prototype[superMethod];
DecoratedClass.prototype[superMethod] =
SuperClass.prototype[superMethod];
}
var calledMethod = function (methodName) {
@@ -772,6 +772,70 @@ S2.define('select2/utils',[
$element.append($nodes);
};
// Cache objects in Utils.__cache instead of $.data (see #4346)
Utils.__cache = {};
var id = 0;
Utils.GetUniqueElementId = function (element) {
// Get a unique element Id. If element has no id,
// creates a new unique number, stores it in the id
// attribute and returns the new id.
// If an id already exists, it simply returns it.
var select2Id = element.getAttribute('data-select2-id');
if (select2Id == null) {
// If element has id, use it.
if (element.id) {
select2Id = element.id;
element.setAttribute('data-select2-id', select2Id);
} else {
element.setAttribute('data-select2-id', ++id);
select2Id = id.toString();
}
}
return select2Id;
};
Utils.StoreData = function (element, name, value) {
// Stores an item in the cache for a specified element.
// name is the cache key.
var id = Utils.GetUniqueElementId(element);
if (!Utils.__cache[id]) {
Utils.__cache[id] = {};
}
Utils.__cache[id][name] = value;
};
Utils.GetData = function (element, name) {
// Retrieves a value from the cache by its key (name)
// name is optional. If no name specified, return
// all cache items for the specified element.
// and for a specified element.
var id = Utils.GetUniqueElementId(element);
if (name) {
if (Utils.__cache[id]) {
if (Utils.__cache[id][name] != null) {
return Utils.__cache[id][name];
}
return $(element).data(name); // Fallback to HTML5 data attribs.
}
return $(element).data(name); // Fallback to HTML5 data attribs.
} else {
return Utils.__cache[id];
}
};
Utils.RemoveData = function (element) {
// Removes all cached items for a specified element.
var id = Utils.GetUniqueElementId(element);
if (Utils.__cache[id] != null) {
delete Utils.__cache[id];
}
element.removeAttribute('data-select2-id');
};
return Utils;
});
@@ -791,7 +855,7 @@ S2.define('select2/results',[
Results.prototype.render = function () {
var $results = $(
'<ul class="select2-results__options" role="tree"></ul>'
'<ul class="select2-results__options" role="listbox"></ul>'
);
if (this.options.get('multiple')) {
@@ -814,7 +878,7 @@ S2.define('select2/results',[
this.hideLoading();
var $message = $(
'<li role="treeitem" aria-live="assertive"' +
'<li role="alert" aria-live="assertive"' +
' class="select2-results__option"></li>'
);
@@ -907,7 +971,7 @@ S2.define('select2/results',[
$options.each(function () {
var $option = $(this);
var item = $.data(this, 'data');
var item = Utils.GetData(this, 'data');
// id needs to be converted to a string when comparing
var id = '' + item.id;
@@ -948,11 +1012,16 @@ S2.define('select2/results',[
option.className = 'select2-results__option';
var attrs = {
'role': 'treeitem',
'role': 'option',
'aria-selected': 'false'
};
if (data.disabled) {
var matches = window.Element.prototype.matches ||
window.Element.prototype.msMatchesSelector ||
window.Element.prototype.webkitMatchesSelector;
if ((data.element != null && matches.call(data.element, ':disabled')) ||
(data.element == null && data.disabled)) {
delete attrs['aria-selected'];
attrs['aria-disabled'] = 'true';
}
@@ -1012,7 +1081,7 @@ S2.define('select2/results',[
this.template(data, option);
}
$.data(option, 'data', data);
Utils.StoreData(option, 'data', data);
return option;
};
@@ -1053,7 +1122,10 @@ S2.define('select2/results',[
}
self.setClasses();
self.highlightFirstItem();
if (self.options.get('scrollAfterSelect')) {
self.highlightFirstItem();
}
});
container.on('unselect', function () {
@@ -1062,7 +1134,10 @@ S2.define('select2/results',[
}
self.setClasses();
self.highlightFirstItem();
if (self.options.get('scrollAfterSelect')) {
self.highlightFirstItem();
}
});
container.on('open', function () {
@@ -1098,7 +1173,7 @@ S2.define('select2/results',[
return;
}
var data = $highlighted.data('data');
var data = Utils.GetData($highlighted[0], 'data');
if ($highlighted.attr('aria-selected') == 'true') {
self.trigger('close', {});
@@ -1116,8 +1191,9 @@ S2.define('select2/results',[
var currentIndex = $options.index($highlighted);
// If we are already at te top, don't move further
if (currentIndex === 0) {
// If we are already at the top, don't move further
// If no options, currentIndex will be -1
if (currentIndex <= 0) {
return;
}
@@ -1210,7 +1286,7 @@ S2.define('select2/results',[
function (evt) {
var $this = $(this);
var data = $this.data('data');
var data = Utils.GetData(this, 'data');
if ($this.attr('aria-selected') === 'true') {
if (self.options.get('multiple')) {
@@ -1233,7 +1309,7 @@ S2.define('select2/results',[
this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
function (evt) {
var data = $(this).data('data');
var data = Utils.GetData(this, 'data');
self.getHighlightedResults()
.removeClass('select2-results__option--highlighted');
@@ -1348,14 +1424,15 @@ S2.define('select2/selection/base',[
this._tabindex = 0;
if (this.$element.data('old-tabindex') != null) {
this._tabindex = this.$element.data('old-tabindex');
if (Utils.GetData(this.$element[0], 'old-tabindex') != null) {
this._tabindex = Utils.GetData(this.$element[0], 'old-tabindex');
} else if (this.$element.attr('tabindex') != null) {
this._tabindex = this.$element.attr('tabindex');
}
$selection.attr('title', this.$element.attr('title'));
$selection.attr('tabindex', this._tabindex);
$selection.attr('aria-disabled', 'false');
this.$selection = $selection;
@@ -1365,7 +1442,6 @@ S2.define('select2/selection/base',[
BaseSelection.prototype.bind = function (container, $container) {
var self = this;
var id = container.id + '-container';
var resultsId = container.id + '-results';
this.container = container;
@@ -1408,17 +1484,19 @@ S2.define('select2/selection/base',[
self.$selection.removeAttr('aria-activedescendant');
self.$selection.removeAttr('aria-owns');
self.$selection.focus();
self.$selection.trigger('focus');
self._detachCloseHandler(container);
});
container.on('enable', function () {
self.$selection.attr('tabindex', self._tabindex);
self.$selection.attr('aria-disabled', 'false');
});
container.on('disable', function () {
self.$selection.attr('tabindex', '-1');
self.$selection.attr('aria-disabled', 'true');
});
};
@@ -1441,7 +1519,6 @@ S2.define('select2/selection/base',[
};
BaseSelection.prototype._attachCloseHandler = function (container) {
var self = this;
$(document.body).on('mousedown.select2.' + container.id, function (e) {
var $target = $(e.target);
@@ -1451,13 +1528,11 @@ S2.define('select2/selection/base',[
var $all = $('.select2.select2-container--open');
$all.each(function () {
var $this = $(this);
if (this == $select[0]) {
return;
}
var $element = $this.data('element');
var $element = Utils.GetData(this, 'element');
$element.select2('close');
});
@@ -1481,6 +1556,27 @@ S2.define('select2/selection/base',[
throw new Error('The `update` method must be defined in child classes.');
};
/**
* Helper method to abstract the "enabled" (not "disabled") state of this
* object.
*
* @return {true} if the instance is not disabled.
* @return {false} if the instance is disabled.
*/
BaseSelection.prototype.isEnabled = function () {
return !this.isDisabled();
};
/**
* Helper method to abstract the "disabled" state of this object.
*
* @return {true} if the disabled option is true.
* @return {false} if the disabled option is false.
*/
BaseSelection.prototype.isDisabled = function () {
return this.options.get('disabled');
};
return BaseSelection;
});
@@ -1518,7 +1614,10 @@ S2.define('select2/selection/single',[
var id = container.id + '-container';
this.$selection.find('.select2-selection__rendered').attr('id', id);
this.$selection.find('.select2-selection__rendered')
.attr('id', id)
.attr('role', 'textbox')
.attr('aria-readonly', 'true');
this.$selection.attr('aria-labelledby', id);
this.$selection.on('mousedown', function (evt) {
@@ -1542,17 +1641,15 @@ S2.define('select2/selection/single',[
container.on('focus', function (evt) {
if (!container.isOpen()) {
self.$selection.focus();
self.$selection.trigger('focus');
}
});
container.on('selection:update', function (params) {
self.update(params.data);
});
};
SingleSelection.prototype.clear = function () {
this.$selection.find('.select2-selection__rendered').empty();
var $rendered = this.$selection.find('.select2-selection__rendered');
$rendered.empty();
$rendered.removeAttr('title'); // clear tooltip on empty
};
SingleSelection.prototype.display = function (data, container) {
@@ -1578,7 +1675,14 @@ S2.define('select2/selection/single',[
var formatted = this.display(selection, $rendered);
$rendered.empty().append(formatted);
$rendered.prop('title', selection.title || selection.text);
var title = selection.title || selection.text;
if (title) {
$rendered.attr('title', title);
} else {
$rendered.removeAttr('title');
}
};
return SingleSelection;
@@ -1623,14 +1727,14 @@ S2.define('select2/selection/multiple',[
'.select2-selection__choice__remove',
function (evt) {
// Ignore the event if it is disabled
if (self.options.get('disabled')) {
if (self.isDisabled()) {
return;
}
var $remove = $(this);
var $selection = $remove.parent();
var data = $selection.data('data');
var data = Utils.GetData($selection[0], 'data');
self.trigger('unselect', {
originalEvent: evt,
@@ -1641,7 +1745,9 @@ S2.define('select2/selection/multiple',[
};
MultipleSelection.prototype.clear = function () {
this.$selection.find('.select2-selection__rendered').empty();
var $rendered = this.$selection.find('.select2-selection__rendered');
$rendered.empty();
$rendered.removeAttr('title');
};
MultipleSelection.prototype.display = function (data, container) {
@@ -1679,9 +1785,14 @@ S2.define('select2/selection/multiple',[
var formatted = this.display(selection, $selection);
$selection.append(formatted);
$selection.prop('title', selection.title || selection.text);
$selection.data('data', selection);
var title = selection.title || selection.text;
if (title) {
$selection.attr('title', title);
}
Utils.StoreData($selection[0], 'data', selection);
$selections.push($selection);
}
@@ -1746,8 +1857,9 @@ S2.define('select2/selection/placeholder',[
S2.define('select2/selection/allowClear',[
'jquery',
'../keys'
], function ($, KEYS) {
'../keys',
'../utils'
], function ($, KEYS, Utils) {
function AllowClear () { }
AllowClear.prototype.bind = function (decorated, container, $container) {
@@ -1776,7 +1888,7 @@ S2.define('select2/selection/allowClear',[
AllowClear.prototype._handleClear = function (_, evt) {
// Ignore the event if it is disabled
if (this.options.get('disabled')) {
if (this.isDisabled()) {
return;
}
@@ -1789,10 +1901,22 @@ S2.define('select2/selection/allowClear',[
evt.stopPropagation();
var data = $clear.data('data');
var data = Utils.GetData($clear[0], 'data');
var previousVal = this.$element.val();
this.$element.val(this.placeholder.id);
var unselectData = {
data: data
};
this.trigger('clear', unselectData);
if (unselectData.prevented) {
this.$element.val(previousVal);
return;
}
for (var d = 0; d < data.length; d++) {
var unselectData = {
unselectData = {
data: data[d]
};
@@ -1802,11 +1926,12 @@ S2.define('select2/selection/allowClear',[
// If the event was prevented, don't clear it out.
if (unselectData.prevented) {
this.$element.val(previousVal);
return;
}
}
this.$element.val(this.placeholder.id).trigger('change');
this.$element.trigger('input').trigger('change');
this.trigger('toggle', {});
};
@@ -1829,12 +1954,14 @@ S2.define('select2/selection/allowClear',[
return;
}
var removeAll = this.options.get('translations').get('removeAllItems');
var $remove = $(
'<span class="select2-selection__clear">' +
'<span class="select2-selection__clear" title="' + removeAll() +'">' +
'&times;' +
'</span>'
);
$remove.data('data', data);
Utils.StoreData($remove[0], 'data', data);
this.$selection.find('.select2-selection__rendered').prepend($remove);
};
@@ -1856,7 +1983,7 @@ S2.define('select2/selection/search',[
'<li class="select2-search select2-search--inline">' +
'<input class="select2-search__field" type="search" tabindex="-1"' +
' autocomplete="off" autocorrect="off" autocapitalize="none"' +
' spellcheck="false" role="textbox" aria-autocomplete="list" />' +
' spellcheck="false" role="searchbox" aria-autocomplete="list" />' +
'</li>'
);
@@ -1873,14 +2000,18 @@ S2.define('select2/selection/search',[
Search.prototype.bind = function (decorated, container, $container) {
var self = this;
var resultsId = container.id + '-results';
decorated.call(this, container, $container);
container.on('open', function () {
self.$search.attr('aria-controls', resultsId);
self.$search.trigger('focus');
});
container.on('close', function () {
self.$search.val('');
self.$search.removeAttr('aria-controls');
self.$search.removeAttr('aria-activedescendant');
self.$search.trigger('focus');
});
@@ -1900,7 +2031,11 @@ S2.define('select2/selection/search',[
});
container.on('results:focus', function (params) {
self.$search.attr('aria-activedescendant', params.id);
if (params.data._resultId) {
self.$search.attr('aria-activedescendant', params.data._resultId);
} else {
self.$search.removeAttr('aria-activedescendant');
}
});
this.$selection.on('focusin', '.select2-search--inline', function (evt) {
@@ -1925,7 +2060,7 @@ S2.define('select2/selection/search',[
.prev('.select2-selection__choice');
if ($previousChoice.length > 0) {
var item = $previousChoice.data('data');
var item = Utils.GetData($previousChoice[0], 'data');
self.searchRemoveChoice(item);
@@ -1934,6 +2069,12 @@ S2.define('select2/selection/search',[
}
});
this.$selection.on('click', '.select2-search--inline', function (evt) {
if (self.$search.val()) {
evt.stopPropagation();
}
});
// Try to detect the IE version should the `documentMode` property that
// is stored on the document. This is only implemented in IE and is
// slightly cleaner than doing a user agent check.
@@ -2019,7 +2160,7 @@ S2.define('select2/selection/search',[
this.resizeSearch();
if (searchHadFocus) {
this.$search.focus();
this.$search.trigger('focus');
}
};
@@ -2052,7 +2193,7 @@ S2.define('select2/selection/search',[
var width = '';
if (this.$search.attr('placeholder') !== '') {
width = this.$selection.find('.select2-selection__rendered').innerWidth();
width = this.$selection.find('.select2-selection__rendered').width();
} else {
var minimumWidth = this.$search.val().length + 1;
@@ -2076,10 +2217,13 @@ S2.define('select2/selection/eventRelay',[
'open', 'opening',
'close', 'closing',
'select', 'selecting',
'unselect', 'unselecting'
'unselect', 'unselecting',
'clear', 'clearing'
];
var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting'];
var preventableEvents = [
'opening', 'closing', 'selecting', 'unselecting', 'clearing'
];
decorated.call(this, container, $container);
@@ -2412,6 +2556,7 @@ S2.define('select2/diacritics',[
'\u019F': 'O',
'\uA74A': 'O',
'\uA74C': 'O',
'\u0152': 'OE',
'\u01A2': 'OI',
'\uA74E': 'OO',
'\u0222': 'OU',
@@ -2821,6 +2966,7 @@ S2.define('select2/diacritics',[
'\uA74B': 'o',
'\uA74D': 'o',
'\u0275': 'o',
'\u0153': 'oe',
'\u01A3': 'oi',
'\u0223': 'ou',
'\uA74F': 'oo',
@@ -2989,8 +3135,9 @@ S2.define('select2/diacritics',[
'\u03CD': '\u03C5',
'\u03CB': '\u03C5',
'\u03B0': '\u03C5',
'\u03C9': '\u03C9',
'\u03C2': '\u03C3'
'\u03CE': '\u03C9',
'\u03C2': '\u03C3',
'\u2019': '\''
};
return diacritics;
@@ -3075,7 +3222,7 @@ S2.define('select2/data/select',[
if ($(data.element).is('option')) {
data.element.selected = true;
this.$element.trigger('change');
this.$element.trigger('input').trigger('change');
return;
}
@@ -3096,13 +3243,13 @@ S2.define('select2/data/select',[
}
self.$element.val(val);
self.$element.trigger('change');
self.$element.trigger('input').trigger('change');
});
} else {
var val = data.id;
this.$element.val(val);
this.$element.trigger('change');
this.$element.trigger('input').trigger('change');
}
};
@@ -3118,7 +3265,7 @@ S2.define('select2/data/select',[
if ($(data.element).is('option')) {
data.element.selected = false;
this.$element.trigger('change');
this.$element.trigger('input').trigger('change');
return;
}
@@ -3136,7 +3283,7 @@ S2.define('select2/data/select',[
self.$element.val(val);
self.$element.trigger('change');
self.$element.trigger('input').trigger('change');
});
};
@@ -3158,7 +3305,7 @@ S2.define('select2/data/select',[
// Remove anything added to child elements
this.$element.find('*').each(function () {
// Remove any custom data set by Select2
$.removeData(this, 'data');
Utils.RemoveData(this);
});
};
@@ -3231,7 +3378,7 @@ S2.define('select2/data/select',[
normalizedData.element = option;
// Override the option's data with the combined data
$.data(option, 'data', normalizedData);
Utils.StoreData(option, 'data', normalizedData);
return $option;
};
@@ -3239,7 +3386,7 @@ S2.define('select2/data/select',[
SelectAdapter.prototype.item = function ($option) {
var data = {};
data = $.data($option[0], 'data');
data = Utils.GetData($option[0], 'data');
if (data != null) {
return data;
@@ -3277,13 +3424,13 @@ S2.define('select2/data/select',[
data = this._normalizeItem(data);
data.element = $option[0];
$.data($option[0], 'data', data);
Utils.StoreData($option[0], 'data', data);
return data;
};
SelectAdapter.prototype._normalizeItem = function (item) {
if (!$.isPlainObject(item)) {
if (item !== Object(item)) {
item = {
id: item,
text: item
@@ -3329,15 +3476,19 @@ S2.define('select2/data/array',[
'jquery'
], function (SelectAdapter, Utils, $) {
function ArrayAdapter ($element, options) {
var data = options.get('data') || [];
this._dataToConvert = options.get('data') || [];
ArrayAdapter.__super__.constructor.call(this, $element, options);
this.addOptions(this.convertToOptions(data));
}
Utils.Extend(ArrayAdapter, SelectAdapter);
ArrayAdapter.prototype.bind = function (container, $container) {
ArrayAdapter.__super__.bind.call(this, container, $container);
this.addOptions(this.convertToOptions(this._dataToConvert));
};
ArrayAdapter.prototype.select = function (data) {
var $option = this.$element.find('option').filter(function (i, elm) {
return elm.value == data.id.toString();
@@ -3487,7 +3638,8 @@ S2.define('select2/data/ajax',[
}, function () {
// Attempt to detect if a request was aborted
// Only works if the transport exposes a status property
if ($request.status && $request.status === '0') {
if ('status' in $request &&
($request.status === 0 || $request.status === '0')) {
return;
}
@@ -3626,8 +3778,6 @@ S2.define('select2/data/tags',[
};
Tags.prototype._removeOldTags = function (_) {
var tag = this._lastTag;
var $options = this.$element.find('option[data-select2-tag]');
$options.each(function () {
@@ -3702,7 +3852,7 @@ S2.define('select2/data/tokenizer',[
// Replace the search term if we have the search box
if (this.$search.length) {
this.$search.val(tokenData.term);
this.$search.focus();
this.$search.trigger('focus');
}
params.term = tokenData.term;
@@ -3831,10 +3981,30 @@ S2.define('select2/data/maximumSelectionLength',[
decorated.call(this, $e, options);
}
MaximumSelectionLength.prototype.bind =
function (decorated, container, $container) {
var self = this;
decorated.call(this, container, $container);
container.on('select', function () {
self._checkIfMaximumSelected();
});
};
MaximumSelectionLength.prototype.query =
function (decorated, params, callback) {
var self = this;
this._checkIfMaximumSelected(function () {
decorated.call(self, params, callback);
});
};
MaximumSelectionLength.prototype._checkIfMaximumSelected =
function (_, successCallback) {
var self = this;
this.current(function (currentData) {
var count = currentData != null ? currentData.length : 0;
if (self.maximumSelectionLength > 0 &&
@@ -3847,7 +4017,10 @@ S2.define('select2/data/maximumSelectionLength',[
});
return;
}
decorated.call(self, params, callback);
if (successCallback) {
successCallback();
}
});
};
@@ -3886,7 +4059,7 @@ S2.define('select2/dropdown',[
};
Dropdown.prototype.position = function ($dropdown, $container) {
// Should be implmented in subclasses
// Should be implemented in subclasses
};
Dropdown.prototype.destroy = function () {
@@ -3910,7 +4083,7 @@ S2.define('select2/dropdown/search',[
'<span class="select2-search select2-search--dropdown">' +
'<input class="select2-search__field" type="search" tabindex="-1"' +
' autocomplete="off" autocorrect="off" autocapitalize="none"' +
' spellcheck="false" role="textbox" />' +
' spellcheck="false" role="searchbox" aria-autocomplete="list" />' +
'</span>'
);
@@ -3925,6 +4098,8 @@ S2.define('select2/dropdown/search',[
Search.prototype.bind = function (decorated, container, $container) {
var self = this;
var resultsId = container.id + '-results';
decorated.call(this, container, $container);
this.$search.on('keydown', function (evt) {
@@ -3947,23 +4122,27 @@ S2.define('select2/dropdown/search',[
container.on('open', function () {
self.$search.attr('tabindex', 0);
self.$search.attr('aria-controls', resultsId);
self.$search.focus();
self.$search.trigger('focus');
window.setTimeout(function () {
self.$search.focus();
self.$search.trigger('focus');
}, 0);
});
container.on('close', function () {
self.$search.attr('tabindex', -1);
self.$search.removeAttr('aria-controls');
self.$search.removeAttr('aria-activedescendant');
self.$search.val('');
self.$search.trigger('blur');
});
container.on('focus', function () {
if (!container.isOpen()) {
self.$search.focus();
self.$search.trigger('focus');
}
});
@@ -3978,6 +4157,14 @@ S2.define('select2/dropdown/search',[
}
}
});
container.on('results:focus', function (params) {
if (params.data._resultId) {
self.$search.attr('aria-activedescendant', params.data._resultId);
} else {
self.$search.removeAttr('aria-activedescendant');
}
});
};
Search.prototype.handleSearch = function (evt) {
@@ -4062,6 +4249,7 @@ S2.define('select2/dropdown/infiniteScroll',[
if (this.showLoadingMore(data)) {
this.$results.append(this.$loadingMore);
this.loadMoreIfNeeded();
}
};
@@ -4080,25 +4268,27 @@ S2.define('select2/dropdown/infiniteScroll',[
self.loading = true;
});
this.$results.on('scroll', function () {
var isLoadMoreVisible = $.contains(
document.documentElement,
self.$loadingMore[0]
);
this.$results.on('scroll', this.loadMoreIfNeeded.bind(this));
};
if (self.loading || !isLoadMoreVisible) {
return;
}
InfiniteScroll.prototype.loadMoreIfNeeded = function () {
var isLoadMoreVisible = $.contains(
document.documentElement,
this.$loadingMore[0]
);
var currentOffset = self.$results.offset().top +
self.$results.outerHeight(false);
var loadingMoreOffset = self.$loadingMore.offset().top +
self.$loadingMore.outerHeight(false);
if (this.loading || !isLoadMoreVisible) {
return;
}
if (currentOffset + 50 >= loadingMoreOffset) {
self.loadMore();
}
});
var currentOffset = this.$results.offset().top +
this.$results.outerHeight(false);
var loadingMoreOffset = this.$loadingMore.offset().top +
this.$loadingMore.outerHeight(false);
if (currentOffset + 50 >= loadingMoreOffset) {
this.loadMore();
}
};
InfiniteScroll.prototype.loadMore = function () {
@@ -4119,7 +4309,7 @@ S2.define('select2/dropdown/infiniteScroll',[
var $option = $(
'<li ' +
'class="select2-results__option select2-results__option--load-more"' +
'role="treeitem" aria-disabled="true"></li>'
'role="option" aria-disabled="true"></li>'
);
var message = this.options.get('translations').get('loadingMore');
@@ -4137,7 +4327,7 @@ S2.define('select2/dropdown/attachBody',[
'../utils'
], function ($, Utils) {
function AttachBody (decorated, $element, options) {
this.$dropdownParent = options.get('dropdownParent') || $(document.body);
this.$dropdownParent = $(options.get('dropdownParent') || document.body);
decorated.call(this, $element, options);
}
@@ -4145,27 +4335,14 @@ S2.define('select2/dropdown/attachBody',[
AttachBody.prototype.bind = function (decorated, container, $container) {
var self = this;
var setupResultsEvents = false;
decorated.call(this, container, $container);
container.on('open', function () {
self._showDropdown();
self._attachPositioningHandler(container);
if (!setupResultsEvents) {
setupResultsEvents = true;
container.on('results:all', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('results:append', function () {
self._positionDropdown();
self._resizeDropdown();
});
}
// Must bind after the results handlers to ensure correct sizing
self._bindContainerResultHandlers(container);
});
container.on('close', function () {
@@ -4214,6 +4391,44 @@ S2.define('select2/dropdown/attachBody',[
this.$dropdownContainer.detach();
};
AttachBody.prototype._bindContainerResultHandlers =
function (decorated, container) {
// These should only be bound once
if (this._containerResultsHandlersBound) {
return;
}
var self = this;
container.on('results:all', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('results:append', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('results:message', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('select', function () {
self._positionDropdown();
self._resizeDropdown();
});
container.on('unselect', function () {
self._positionDropdown();
self._resizeDropdown();
});
this._containerResultsHandlersBound = true;
};
AttachBody.prototype._attachPositioningHandler =
function (decorated, container) {
var self = this;
@@ -4224,14 +4439,14 @@ S2.define('select2/dropdown/attachBody',[
var $watchers = this.$container.parents().filter(Utils.hasScroll);
$watchers.each(function () {
$(this).data('select2-scroll-position', {
Utils.StoreData(this, 'select2-scroll-position', {
x: $(this).scrollLeft(),
y: $(this).scrollTop()
});
});
$watchers.on(scrollEvent, function (ev) {
var position = $(this).data('select2-scroll-position');
var position = Utils.GetData(this, 'select2-scroll-position');
$(this).scrollTop(position.y);
});
@@ -4290,16 +4505,26 @@ S2.define('select2/dropdown/attachBody',[
top: container.bottom
};
// Determine what the parent element is to use for calciulating the offset
// Determine what the parent element is to use for calculating the offset
var $offsetParent = this.$dropdownParent;
// For statically positoned elements, we need to get the element
// For statically positioned elements, we need to get the element
// that is determining the offset
if ($offsetParent.css('position') === 'static') {
$offsetParent = $offsetParent.offsetParent();
}
var parentOffset = $offsetParent.offset();
var parentOffset = {
top: 0,
left: 0
};
if (
$.contains(document.body, $offsetParent[0]) ||
$offsetParent[0].isConnected
) {
parentOffset = $offsetParent.offset();
}
css.top -= parentOffset.top;
css.left -= parentOffset.left;
@@ -4396,8 +4621,8 @@ S2.define('select2/dropdown/minimumResultsForSearch',[
});
S2.define('select2/dropdown/selectOnClose',[
], function () {
'../utils'
], function (Utils) {
function SelectOnClose () { }
SelectOnClose.prototype.bind = function (decorated, container, $container) {
@@ -4428,7 +4653,7 @@ S2.define('select2/dropdown/selectOnClose',[
return;
}
var data = $highlightedResults.data('data');
var data = Utils.GetData($highlightedResults[0], 'data');
// Don't re-select already selected resulte
if (
@@ -4469,7 +4694,7 @@ S2.define('select2/dropdown/closeOnSelect',[
var originalEvent = evt.originalEvent;
// Don't close if the control key is being held
if (originalEvent && originalEvent.ctrlKey) {
if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) {
return;
}
@@ -4523,6 +4748,9 @@ S2.define('select2/i18n/en',[],function () {
},
searching: function () {
return 'Searching…';
},
removeAllItems: function () {
return 'Remove all items';
}
};
});
@@ -4761,66 +4989,29 @@ S2.define('select2/defaults',[
);
}
if (typeof options.language === 'string') {
// Check if the language is specified with a region
if (options.language.indexOf('-') > 0) {
// Extract the region information if it is included
var languageParts = options.language.split('-');
var baseLanguage = languageParts[0];
// If the defaults were not previously applied from an element, it is
// possible for the language option to have not been resolved
options.language = this._resolveLanguage(options.language);
options.language = [options.language, baseLanguage];
} else {
options.language = [options.language];
// Always fall back to English since it will always be complete
options.language.push('en');
var uniqueLanguages = [];
for (var l = 0; l < options.language.length; l++) {
var language = options.language[l];
if (uniqueLanguages.indexOf(language) === -1) {
uniqueLanguages.push(language);
}
}
if ($.isArray(options.language)) {
var languages = new Translation();
options.language.push('en');
options.language = uniqueLanguages;
var languageNames = options.language;
for (var l = 0; l < languageNames.length; l++) {
var name = languageNames[l];
var language = {};
try {
// Try to load it with the original name
language = Translation.loadPath(name);
} catch (e) {
try {
// If we couldn't load it, check if it wasn't the full path
name = this.defaults.amdLanguageBase + name;
language = Translation.loadPath(name);
} catch (ex) {
// The translation could not be loaded at all. Sometimes this is
// because of a configuration problem, other times this can be
// because of how Select2 helps load all possible translation files.
if (options.debug && window.console && console.warn) {
console.warn(
'Select2: The language file for "' + name + '" could not be ' +
'automatically loaded. A fallback will be used instead.'
);
}
continue;
}
}
languages.extend(language);
}
options.translations = languages;
} else {
var baseTranslation = Translation.loadPath(
this.defaults.amdLanguageBase + 'en'
);
var customTranslation = new Translation(options.language);
customTranslation.extend(baseTranslation);
options.translations = customTranslation;
}
options.translations = this._processTranslations(
options.language,
options.debug
);
return options;
};
@@ -4887,13 +5078,14 @@ S2.define('select2/defaults',[
debug: false,
dropdownAutoWidth: false,
escapeMarkup: Utils.escapeMarkup,
language: EnglishTranslation,
language: {},
matcher: matcher,
minimumInputLength: 0,
maximumInputLength: 0,
maximumSelectionLength: 0,
minimumResultsForSearch: 0,
selectOnClose: false,
scrollAfterSelect: false,
sorter: function (data) {
return data;
},
@@ -4908,6 +5100,103 @@ S2.define('select2/defaults',[
};
};
Defaults.prototype.applyFromElement = function (options, $element) {
var optionLanguage = options.language;
var defaultLanguage = this.defaults.language;
var elementLanguage = $element.prop('lang');
var parentLanguage = $element.closest('[lang]').prop('lang');
var languages = Array.prototype.concat.call(
this._resolveLanguage(elementLanguage),
this._resolveLanguage(optionLanguage),
this._resolveLanguage(defaultLanguage),
this._resolveLanguage(parentLanguage)
);
options.language = languages;
return options;
};
Defaults.prototype._resolveLanguage = function (language) {
if (!language) {
return [];
}
if ($.isEmptyObject(language)) {
return [];
}
if ($.isPlainObject(language)) {
return [language];
}
var languages;
if (!$.isArray(language)) {
languages = [language];
} else {
languages = language;
}
var resolvedLanguages = [];
for (var l = 0; l < languages.length; l++) {
resolvedLanguages.push(languages[l]);
if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) {
// Extract the region information if it is included
var languageParts = languages[l].split('-');
var baseLanguage = languageParts[0];
resolvedLanguages.push(baseLanguage);
}
}
return resolvedLanguages;
};
Defaults.prototype._processTranslations = function (languages, debug) {
var translations = new Translation();
for (var l = 0; l < languages.length; l++) {
var languageData = new Translation();
var language = languages[l];
if (typeof language === 'string') {
try {
// Try to load it with the original name
languageData = Translation.loadPath(language);
} catch (e) {
try {
// If we couldn't load it, check if it wasn't the full path
language = this.defaults.amdLanguageBase + language;
languageData = Translation.loadPath(language);
} catch (ex) {
// The translation could not be loaded at all. Sometimes this is
// because of a configuration problem, other times this can be
// because of how Select2 helps load all possible translation files
if (debug && window.console && console.warn) {
console.warn(
'Select2: The language file for "' + language + '" could ' +
'not be automatically loaded. A fallback will be used instead.'
);
}
}
}
} else if ($.isPlainObject(language)) {
languageData = new Translation(language);
} else {
languageData = language;
}
translations.extend(languageData);
}
return translations;
};
Defaults.prototype.set = function (key, value) {
var camelKey = $.camelCase(key);
@@ -4916,7 +5205,7 @@ S2.define('select2/defaults',[
var convertedData = Utils._convertData(data);
$.extend(this.defaults, convertedData);
$.extend(true, this.defaults, convertedData);
};
var defaults = new Defaults();
@@ -4937,6 +5226,10 @@ S2.define('select2/options',[
this.fromElement($element);
}
if ($element != null) {
this.options = Defaults.applyFromElement(this.options, $element);
}
this.options = Defaults.apply(this.options);
if ($element && $element.is('input')) {
@@ -4960,14 +5253,6 @@ S2.define('select2/options',[
this.options.disabled = $e.prop('disabled');
}
if (this.options.language == null) {
if ($e.prop('lang')) {
this.options.language = $e.prop('lang').toLowerCase();
} else if ($e.closest('[lang]').prop('lang')) {
this.options.language = $e.closest('[lang]').prop('lang');
}
}
if (this.options.dir == null) {
if ($e.prop('dir')) {
this.options.dir = $e.prop('dir');
@@ -4981,7 +5266,7 @@ S2.define('select2/options',[
$e.prop('disabled', this.options.disabled);
$e.prop('multiple', this.options.multiple);
if ($e.data('select2Tags')) {
if (Utils.GetData($e[0], 'select2Tags')) {
if (this.options.debug && window.console && console.warn) {
console.warn(
'Select2: The `data-select2-tags` attribute has been changed to ' +
@@ -4990,11 +5275,11 @@ S2.define('select2/options',[
);
}
$e.data('data', $e.data('select2Tags'));
$e.data('tags', true);
Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags'));
Utils.StoreData($e[0], 'tags', true);
}
if ($e.data('ajaxUrl')) {
if (Utils.GetData($e[0], 'ajaxUrl')) {
if (this.options.debug && window.console && console.warn) {
console.warn(
'Select2: The `data-ajax-url` attribute has been changed to ' +
@@ -5003,21 +5288,45 @@ S2.define('select2/options',[
);
}
$e.attr('ajax--url', $e.data('ajaxUrl'));
$e.data('ajax--url', $e.data('ajaxUrl'));
$e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl'));
Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl'));
}
var dataset = {};
function upperCaseLetter(_, letter) {
return letter.toUpperCase();
}
// Pre-load all of the attributes which are prefixed with `data-`
for (var attr = 0; attr < $e[0].attributes.length; attr++) {
var attributeName = $e[0].attributes[attr].name;
var prefix = 'data-';
if (attributeName.substr(0, prefix.length) == prefix) {
// Get the contents of the attribute after `data-`
var dataName = attributeName.substring(prefix.length);
// Get the data contents from the consistent source
// This is more than likely the jQuery data helper
var dataValue = Utils.GetData($e[0], dataName);
// camelCase the attribute name to match the spec
var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter);
// Store the data attribute contents into the dataset since
dataset[camelDataName] = dataValue;
}
}
// Prefer the element's `dataset` attribute if it exists
// jQuery 1.x does not correctly handle data attributes with multiple dashes
if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) {
dataset = $.extend(true, {}, $e[0].dataset, $e.data());
} else {
dataset = $e.data();
dataset = $.extend(true, {}, $e[0].dataset, dataset);
}
var data = $.extend(true, {}, dataset);
// Prefer our internal data cache if it exists
var data = $.extend(true, {}, Utils.GetData($e[0]), dataset);
data = Utils._convertData(data);
@@ -5054,8 +5363,8 @@ S2.define('select2/core',[
'./keys'
], function ($, Options, Utils, KEYS) {
var Select2 = function ($element, options) {
if ($element.data('select2') != null) {
$element.data('select2').destroy();
if (Utils.GetData($element[0], 'select2') != null) {
Utils.GetData($element[0], 'select2').destroy();
}
this.$element = $element;
@@ -5071,7 +5380,7 @@ S2.define('select2/core',[
// Set up the tabindex
var tabindex = $element.attr('tabindex') || 0;
$element.data('old-tabindex', tabindex);
Utils.StoreData($element[0], 'old-tabindex', tabindex);
$element.attr('tabindex', '-1');
// Set up containers and adapters
@@ -5132,6 +5441,9 @@ S2.define('select2/core',[
// Synchronize any monitored attributes
this._syncAttributes();
Utils.StoreData($element[0], 'select2', this);
// Ensure backwards compatibility with $element.data('select2').
$element.data('select2', this);
};
@@ -5208,6 +5520,12 @@ S2.define('select2/core',[
return null;
}
if (method == 'computedstyle') {
var computedStyle = window.getComputedStyle($element[0]);
return computedStyle.width;
}
return method;
};
@@ -5248,8 +5566,8 @@ S2.define('select2/core',[
if (observer != null) {
this._observer = new observer(function (mutations) {
$.each(mutations, self._syncA);
$.each(mutations, self._syncS);
self._syncA();
self._syncS(null, mutations);
});
this._observer.observe(this.$element[0], {
attributes: true,
@@ -5371,7 +5689,7 @@ S2.define('select2/core',[
if (self.isOpen()) {
if (key === KEYS.ESC || key === KEYS.TAB ||
(key === KEYS.UP && evt.altKey)) {
self.close();
self.close(evt);
evt.preventDefault();
} else if (key === KEYS.ENTER) {
@@ -5405,7 +5723,7 @@ S2.define('select2/core',[
Select2.prototype._syncAttributes = function () {
this.options.set('disabled', this.$element.prop('disabled'));
if (this.options.get('disabled')) {
if (this.isDisabled()) {
if (this.isOpen()) {
this.close();
}
@@ -5416,7 +5734,7 @@ S2.define('select2/core',[
}
};
Select2.prototype._syncSubtree = function (evt, mutations) {
Select2.prototype._isChangeMutation = function (evt, mutations) {
var changed = false;
var self = this;
@@ -5444,7 +5762,22 @@ S2.define('select2/core',[
}
} else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
changed = true;
} else if ($.isArray(mutations)) {
$.each(mutations, function(evt, mutation) {
if (self._isChangeMutation(evt, mutation)) {
// We've found a change mutation.
// Let's escape from the loop and continue
changed = true;
return false;
}
});
}
return changed;
};
Select2.prototype._syncSubtree = function (evt, mutations) {
var changed = this._isChangeMutation(evt, mutations);
var self = this;
// Only re-pull the data if we think there is a change
if (changed) {
@@ -5466,7 +5799,8 @@ S2.define('select2/core',[
'open': 'opening',
'close': 'closing',
'select': 'selecting',
'unselect': 'unselecting'
'unselect': 'unselecting',
'clear': 'clearing'
};
if (args === undefined) {
@@ -5494,7 +5828,7 @@ S2.define('select2/core',[
};
Select2.prototype.toggleDropdown = function () {
if (this.options.get('disabled')) {
if (this.isDisabled()) {
return;
}
@@ -5510,15 +5844,40 @@ S2.define('select2/core',[
return;
}
if (this.isDisabled()) {
return;
}
this.trigger('query', {});
};
Select2.prototype.close = function () {
Select2.prototype.close = function (evt) {
if (!this.isOpen()) {
return;
}
this.trigger('close', {});
this.trigger('close', { originalEvent : evt });
};
/**
* Helper method to abstract the "enabled" (not "disabled") state of this
* object.
*
* @return {true} if the instance is not disabled.
* @return {false} if the instance is disabled.
*/
Select2.prototype.isEnabled = function () {
return !this.isDisabled();
};
/**
* Helper method to abstract the "disabled" state of this object.
*
* @return {true} if the disabled option is true.
* @return {false} if the disabled option is false.
*/
Select2.prototype.isDisabled = function () {
return this.options.get('disabled');
};
Select2.prototype.isOpen = function () {
@@ -5595,7 +5954,7 @@ S2.define('select2/core',[
});
}
this.$element.val(newVal).trigger('change');
this.$element.val(newVal).trigger('input').trigger('change');
};
Select2.prototype.destroy = function () {
@@ -5621,10 +5980,12 @@ S2.define('select2/core',[
this._syncS = null;
this.$element.off('.select2');
this.$element.attr('tabindex', this.$element.data('old-tabindex'));
this.$element.attr('tabindex',
Utils.GetData(this.$element[0], 'old-tabindex'));
this.$element.removeClass('select2-hidden-accessible');
this.$element.attr('aria-hidden', 'false');
Utils.RemoveData(this.$element[0]);
this.$element.removeData('select2');
this.dataAdapter.destroy();
@@ -5652,7 +6013,7 @@ S2.define('select2/core',[
this.$container.addClass('select2-container--' + this.options.get('theme'));
$container.data('element', this.$element);
Utils.StoreData($container[0], 'element', this.$element);
return $container;
};
@@ -5672,8 +6033,9 @@ S2.define('jquery.select2',[
'jquery-mousewheel',
'./select2/core',
'./select2/defaults'
], function ($, _, Select2, Defaults) {
'./select2/defaults',
'./select2/utils'
], function ($, _, Select2, Defaults, Utils) {
if ($.fn.select2 == null) {
// All methods that should return the element
var thisMethods = ['open', 'close', 'destroy'];
@@ -5694,7 +6056,7 @@ S2.define('jquery.select2',[
var args = Array.prototype.slice.call(arguments, 1);
this.each(function () {
var instance = $(this).data('select2');
var instance = Utils.GetData(this, 'select2');
if (instance == null && window.console && console.error) {
console.error(
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -117,7 +117,7 @@ function logError(string $err, string $errstr, string $errpath, array $trace)
]);
}
function logErrorByCustomHandler(int $errno, string $errstr, string $errfile, int $errline, array $errcontext)
function logErrorByCustomHandler(int $errno, string $errstr, string $errfile, int $errline, array $errcontext=null)
{
if (!(error_reporting() & $errno)) {
// This error code is not included in error_reporting, so let it fall
+313 -305
View File
@@ -1,305 +1,313 @@
<?php
namespace sammo;
require(__DIR__ . '/../vendor/autoload.php');
$host = Util::getPost('db_host');
$port = Util::getPost('db_port', 'int');
$username = Util::getPost('db_id');
$password = Util::getPost('db_pw');
$dbName = Util::getPost('db_name');
$servHost = Util::getPost('serv_host');
$sharedIconPath = Util::getPost('shared_icon_path');
$gameImagePath = Util::getPost('game_image_path');
$imageRequestKey = Util::getPost('image_request_key');
$kakaoRESTKey = Util::getPost('kakao_rest_key', 'string', '');
$kakaoAdminKey = Util::getPost('kakao_admin_key', 'string', '');
if (!$host || !$port || !$username || !$password || !$dbName || !$servHost || !$sharedIconPath || !$gameImagePath) {
Json::die([
'result' => false,
'reason' => '입력 값이 올바르지 않습니다'
]);
}
if (!filter_var($servHost, FILTER_VALIDATE_URL)) {
Json::die([
'result' => false,
'reason' => '접속 경로가 올바르지 않습니다.'
]);
}
if (file_exists(ROOT . '/d_setting/RootDB.php') && is_dir(ROOT . '/d_setting/RootDB.php')) {
Json::die([
'result' => false,
'reason' => 'd_setting/RootDB.php 가 디렉토리입니다'
]);
}
if (class_exists('\\sammo\\RootDB')) {
Json::die([
'result' => false,
'reason' => '이미 RootDB.php 파일이 있습니다'
]);
}
//파일 권한 검사
if (file_exists(AppConf::getUserIconPathFS()) && !is_dir(AppConf::getUserIconPathFS())) {
Json::die([
'result' => false,
'reason' => AppConf::$userIconPath . ' 이 디렉토리가 아닙니다'
]);
}
if (file_exists(ROOT . '/d_log') && !is_dir(ROOT . '/d_log')) {
Json::die([
'result' => false,
'reason' => 'd_log 가 디렉토리가 아닙니다'
]);
}
if (file_exists(ROOT . '/d_shared') && !is_dir(ROOT . '/d_shared')) {
Json::die([
'result' => false,
'reason' => 'd_shared 가 디렉토리가 아닙니다'
]);
}
if (file_exists(ROOT . '/d_setting') && !is_dir(ROOT . '/d_setting')) {
Json::die([
'result' => false,
'reason' => 'd_shared 가 디렉토리가 아닙니다'
]);
}
if (
!file_exists(ROOT . '/d_log')
|| !file_exists(ROOT . '/d_shared')
|| !file_exists(ROOT . '/d_setting')
|| !file_exists(AppConf::getUserIconPathFS())
) {
if (!is_writable(ROOT)) {
Json::die([
'result' => false,
'reason' => '하위 디렉토리 생성 권한이 없습니다'
]);
}
//기본 파일 생성
if (!file_exists(AppConf::getUserIconPathFS())) {
mkdir(AppConf::getUserIconPathFS());
}
if (!file_exists(ROOT . '/d_log')) {
mkdir(ROOT . '/d_log');
}
if (!file_exists(ROOT . '/d_setting')) {
mkdir(ROOT . '/d_setting');
}
if (!file_exists(ROOT . '/d_shared')) {
mkdir(ROOT . '/d_shared');
}
}
if (!is_writable(AppConf::getUserIconPathFS())) {
Json::die([
'result' => false,
'reason' => AppConf::$userIconPath . ' 디렉토리의 쓰기 권한이 없습니다'
]);
}
if (!is_writable(ROOT . '/d_log')) {
Json::die([
'result' => false,
'reason' => 'd_log 디렉토리의 쓰기 권한이 없습니다'
]);
}
if (!is_writable(ROOT . '/d_shared')) {
Json::die([
'result' => false,
'reason' => 'd_shared 디렉토리의 쓰기 권한이 없습니다'
]);
}
if (!is_writable(ROOT . '/d_setting')) {
Json::die([
'result' => false,
'reason' => 'd_setting 디렉토리의 쓰기 권한이 없습니다.'
]);
}
if (!file_exists(ROOT . '/d_log/.htaccess')) {
@file_put_contents(ROOT . '/d_log/.htaccess', 'Deny from all');
}
if (!file_exists(ROOT . '/d_setting/.htaccess')) {
@file_put_contents(ROOT . '/d_setting/.htaccess', 'Deny from all');
}
//DB 접근 권한 검사
$rootDB = new \MeekroDB($host, $username, $password, $dbName, $port, 'utf8mb4');
$rootDB->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true;
$rootDB->throw_exception_on_nonsql_error = false;
$rootDB->nonsql_error_handler = function ($params) {
Json::die([
'result' => false,
'reason' => 'DB 접속에 실패했습니다.'
]);
};
$rootDB->error_handler = function ($params) {
Json::die([
'result' => false,
'reason' => 'SQL을 제대로 실행하지 못했습니다. DB상태를 확인해 주세요.'
]);
};
$mysqli_obj = $rootDB->get(); //로그인에 실패할 경우 자동으로 dbConnFail()이 실행됨.
if ($mysqli_obj->multi_query(file_get_contents(__DIR__ . '/sql/common_schema.sql'))) {
while (true) {
if (!$mysqli_obj->more_results()) {
break;
}
if (!$mysqli_obj->next_result()) {
break;
}
}
}
$rootDB->insert('system', array(
'REG' => 'N',
'LOGIN' => 'N',
'CRT_DATE' => TimeUtil::now(),
'MDF_DATE' => TimeUtil::now()
));
$globalSalt = bin2hex(random_bytes(16));
'@phan-var-force string $servHost';
'@phan-var-force string $sharedIconPath';
'@phan-var-force string $gameImagePath';
$sharedIconPath = WebUtil::resolveRelativePath($sharedIconPath, $servHost);
$gameImagePath = WebUtil::resolveRelativePath($gameImagePath, $servHost);
$imageRequestPath = WebUtil::resolveRelativePath($gameImagePath . '/../hook/git_pull.php', $servHost);
$imageKeyInstallPath = WebUtil::resolveRelativePath($gameImagePath . '/../hook/InstallKey.php', $servHost);
$result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/ServConfig.orig.php',
ROOT . '/d_setting/ServConfig.php',
[
'serverBasePath' => $servHost,
'sharedIconPath' => $sharedIconPath,
'gameImagePath' => $gameImagePath,
'imageRequestPath' => $imageRequestPath,
'imageRequestKey' => $imageRequestKey
],
true
);
if ($imageRequestKey) {
@file_get_contents($imageKeyInstallPath . '?key=' . $imageRequestKey);
}
if ($result !== true) {
Json::die([
'result' => false,
'reason' => $result
]);
}
$result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/common_path.orig.js',
ROOT . '/d_shared/common_path.js',
[
'serverBasePath' => $servHost,
'sharedIconPath' => $sharedIconPath,
'gameImagePath' => $gameImagePath
],
true
);
$result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/menu.orig.json',
ROOT . '/d_shared/menu.json',
[],
true
);
if ($result !== true) {
Json::die([
'result' => false,
'reason' => $result
]);
}
$result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/common.orig.css',
ROOT . '/d_shared/common.css',
[
'serverBasePath' => $servHost,
'sharedIconPath' => $sharedIconPath,
'gameImagePath' => $gameImagePath
],
true
);
if ($result !== true) {
Json::die([
'result' => false,
'reason' => $result
]);
}
$result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/RootDB.orig.php',
ROOT . '/d_setting/RootDB.php',
[
'host' => $host,
'user' => $username,
'password' => $password,
'dbName' => $dbName,
'port' => $port,
'globalSalt' => $globalSalt,
]
);
$kakaoRedirectURI = WebUtil::resolveRelativePath('oauth_kakao/oauth.php', $servHost . '/');
Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/KakaoKey.orig.php',
ROOT . '/d_setting/KakaoKey.php',
[
'REST_API_KEY' => $kakaoRESTKey,
'ADMIN_KEY' => $kakaoAdminKey,
'REDIRECT_URI' => $kakaoRedirectURI
],
true
);
if ($result !== true) {
Json::die([
'result' => false,
'reason' => $result
]);
}
Json::die([
'result' => true,
'reason' => 'success',
'globalSalt' => $globalSalt
]);
<?php
namespace sammo;
require(__DIR__ . '/../vendor/autoload.php');
$host = Util::getPost('db_host');
$port = Util::getPost('db_port', 'int');
$username = Util::getPost('db_id');
$password = Util::getPost('db_pw');
$dbName = Util::getPost('db_name');
$servHost = Util::getPost('serv_host');
$sharedIconPath = Util::getPost('shared_icon_path');
$gameImagePath = Util::getPost('game_image_path');
$imageRequestKey = Util::getPost('image_request_key');
$kakaoRESTKey = Util::getPost('kakao_rest_key', 'string', '');
$kakaoAdminKey = Util::getPost('kakao_admin_key', 'string', '');
if (!$host || !$port || !$username || !$password || !$dbName || !$servHost || !$sharedIconPath || !$gameImagePath) {
Json::die([
'result' => false,
'reason' => '입력 값이 올바르지 않습니다'
]);
}
if (!filter_var($servHost, FILTER_VALIDATE_URL)) {
Json::die([
'result' => false,
'reason' => '접속 경로가 올바르지 않습니다.'
]);
}
if (file_exists(ROOT . '/d_setting/RootDB.php') && is_dir(ROOT . '/d_setting/RootDB.php')) {
Json::die([
'result' => false,
'reason' => 'd_setting/RootDB.php 가 디렉토리입니다'
]);
}
if (class_exists('\\sammo\\RootDB')) {
Json::die([
'result' => false,
'reason' => '이미 RootDB.php 파일이 있습니다'
]);
}
//파일 권한 검사
if (file_exists(AppConf::getUserIconPathFS()) && !is_dir(AppConf::getUserIconPathFS())) {
Json::die([
'result' => false,
'reason' => AppConf::$userIconPath . ' 이 디렉토리가 아닙니다'
]);
}
if (file_exists(ROOT . '/d_log') && !is_dir(ROOT . '/d_log')) {
Json::die([
'result' => false,
'reason' => 'd_log 가 디렉토리가 아닙니다'
]);
}
if (file_exists(ROOT . '/d_shared') && !is_dir(ROOT . '/d_shared')) {
Json::die([
'result' => false,
'reason' => 'd_shared 가 디렉토리가 아닙니다'
]);
}
if (file_exists(ROOT . '/d_setting') && !is_dir(ROOT . '/d_setting')) {
Json::die([
'result' => false,
'reason' => 'd_shared 가 디렉토리가 아닙니다'
]);
}
if (
!file_exists(ROOT . '/d_log')
|| !file_exists(ROOT . '/d_shared')
|| !file_exists(ROOT . '/d_setting')
|| !file_exists(AppConf::getUserIconPathFS())
) {
if (!is_writable(ROOT)) {
Json::die([
'result' => false,
'reason' => '하위 디렉토리 생성 권한이 없습니다'
]);
}
//기본 파일 생성
if (!file_exists(AppConf::getUserIconPathFS())) {
mkdir(AppConf::getUserIconPathFS());
}
if (!file_exists(ROOT . '/d_log')) {
mkdir(ROOT . '/d_log');
}
if (!file_exists(ROOT . '/d_setting')) {
mkdir(ROOT . '/d_setting');
}
if (!file_exists(ROOT . '/d_shared')) {
mkdir(ROOT . '/d_shared');
}
}
if (!is_writable(AppConf::getUserIconPathFS())) {
Json::die([
'result' => false,
'reason' => AppConf::$userIconPath . ' 디렉토리의 쓰기 권한이 없습니다'
]);
}
if (!is_writable(ROOT . '/d_log')) {
Json::die([
'result' => false,
'reason' => 'd_log 디렉토리의 쓰기 권한이 없습니다'
]);
}
if (!is_writable(ROOT . '/d_shared')) {
Json::die([
'result' => false,
'reason' => 'd_shared 디렉토리의 쓰기 권한이 없습니다'
]);
}
if (!is_writable(ROOT . '/d_setting')) {
Json::die([
'result' => false,
'reason' => 'd_setting 디렉토리의 쓰기 권한이 없습니다.'
]);
}
if (!file_exists(ROOT . '/d_log/.htaccess')) {
@file_put_contents(ROOT . '/d_log/.htaccess', 'Deny from all');
}
if (!file_exists(ROOT . '/d_setting/.htaccess')) {
@file_put_contents(ROOT . '/d_setting/.htaccess', 'Deny from all');
}
//DB 접근 권한 검사
$rootDB = new \MeekroDB($host, $username, $password, $dbName, $port, 'utf8mb4');
$rootDB->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true;
$rootDB->throw_exception_on_nonsql_error = false;
$rootDB->nonsql_error_handler = function ($params) {
Json::die([
'result' => false,
'reason' => 'DB 접속에 실패했습니다.'
]);
};
$rootDB->error_handler = function ($params) {
Json::die([
'result' => false,
'reason' => 'SQL을 제대로 실행하지 못했습니다. DB상태를 확인해 주세요.'
]);
};
$mysqli_obj = $rootDB->get(); //로그인에 실패할 경우 자동으로 dbConnFail()이 실행됨.
if ($mysqli_obj->multi_query(file_get_contents(__DIR__ . '/sql/common_schema.sql'))) {
while (true) {
if (!$mysqli_obj->more_results()) {
break;
}
if (!$mysqli_obj->next_result()) {
break;
}
}
}
$rootDB->insert('system', array(
'REG' => 'N',
'LOGIN' => 'N',
'CRT_DATE' => TimeUtil::now(),
'MDF_DATE' => TimeUtil::now()
));
$globalSalt = bin2hex(random_bytes(16));
'@phan-var-force string $servHost';
'@phan-var-force string $sharedIconPath';
'@phan-var-force string $gameImagePath';
$sharedIconPath = WebUtil::resolveRelativePath($sharedIconPath, $servHost);
$gameImagePath = WebUtil::resolveRelativePath($gameImagePath, $servHost);
$imageRequestPath = WebUtil::resolveRelativePath($gameImagePath . '/../hook/git_pull.php', $servHost);
$imageKeyInstallPath = WebUtil::resolveRelativePath($gameImagePath . '/../hook/InstallKey.php', $servHost);
$result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/ServConfig.orig.php',
ROOT . '/d_setting/ServConfig.php',
[
'serverBasePath' => $servHost,
'sharedIconPath' => $sharedIconPath,
'gameImagePath' => $gameImagePath,
'imageRequestPath' => $imageRequestPath,
'imageRequestKey' => $imageRequestKey,
'serverList' => [
['che', '체', 'white'],
['kwe', '퀘', 'yellow'],
['pwe', '풰', 'orange'],
['twe', '퉤', 'magenta'],
['nya', '냐', '#e67e22'],
['pya', '퍄', '#9b59b6']
]
],
true
);
if ($imageRequestKey) {
@file_get_contents($imageKeyInstallPath . '?key=' . $imageRequestKey);
}
if ($result !== true) {
Json::die([
'result' => false,
'reason' => $result
]);
}
$result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/common_path.orig.js',
ROOT . '/d_shared/common_path.js',
[
'serverBasePath' => $servHost,
'sharedIconPath' => $sharedIconPath,
'gameImagePath' => $gameImagePath
],
true
);
$result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/menu.orig.json',
ROOT . '/d_shared/menu.json',
[],
true
);
if ($result !== true) {
Json::die([
'result' => false,
'reason' => $result
]);
}
$result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/common.orig.css',
ROOT . '/d_shared/common.css',
[
'serverBasePath' => $servHost,
'sharedIconPath' => $sharedIconPath,
'gameImagePath' => $gameImagePath
],
true
);
if ($result !== true) {
Json::die([
'result' => false,
'reason' => $result
]);
}
$result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/RootDB.orig.php',
ROOT . '/d_setting/RootDB.php',
[
'host' => $host,
'user' => $username,
'password' => $password,
'dbName' => $dbName,
'port' => $port,
'globalSalt' => $globalSalt,
]
);
$kakaoRedirectURI = WebUtil::resolveRelativePath('oauth_kakao/oauth.php', $servHost . '/');
Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/KakaoKey.orig.php',
ROOT . '/d_setting/KakaoKey.php',
[
'REST_API_KEY' => $kakaoRESTKey,
'ADMIN_KEY' => $kakaoAdminKey,
'REDIRECT_URI' => $kakaoRedirectURI
],
true
);
if ($result !== true) {
Json::die([
'result' => false,
'reason' => $result
]);
}
Json::die([
'result' => true,
'reason' => 'success',
'globalSalt' => $globalSalt
]);
+74 -55
View File
@@ -1,55 +1,74 @@
<?php
namespace sammo;
class ServConfig
{
private function __construct()
{
}
public static $serverWebPath = '_tK_serverBasePath_';
public static $sharedIconPath = '_tK_sharedIconPath_';
public static $gameImagePath = "_tK_gameImagePath_";
public static $imageRequestPath = "_tK_imageRequestPath_";
public static $imageRequestKey = '_tK_imageRequestKey_';
public static function getSharedIconPath(string $filepath = ''): string
{
if ($filepath) {
return static::$sharedIconPath . "/{$filepath}";
}
return static::$sharedIconPath;
}
public static function getUserIconPath(string $filepath = ''): string
{
return AppConf::getUserIconPathWeb($filepath);
}
public static function getGameImagePath(string $filepath = ''): string
{
if ($filepath) {
return static::$gameImagePath . "/{$filepath}";
}
return static::$gameImagePath;
}
public static function getImagePullURI(): string
{
$now = time();
$req_hash = Util::hashPassword(sprintf("%016x", $now), static::$imageRequestKey);
return static::$imageRequestPath . "?req={$req_hash}&time={$now}";
}
/**
* 서버 주소 반환. 서버의 경로가 하부 디렉토리인 경우에 하부 디렉토리까지 포함
*
* @return string
*/
public static function getServerBasepath(): string
{
return self::$serverWebPath;
}
}
<?php
namespace sammo;
class ServConfig
{
private function __construct()
{
}
public static $serverWebPath = '_tK_serverBasePath_';
public static $sharedIconPath = '_tK_sharedIconPath_';
public static $gameImagePath = "_tK_gameImagePath_";
public static $imageRequestPath = "_tK_imageRequestPath_";
public static $imageRequestKey = '_tK_imageRequestKey_';
private static $serverList = null;
public static function getSharedIconPath(string $filepath = ''): string
{
if ($filepath) {
return static::$sharedIconPath . "/{$filepath}";
}
return static::$sharedIconPath;
}
public static function getUserIconPath(string $filepath = ''): string
{
return AppConf::getUserIconPathWeb($filepath);
}
public static function getGameImagePath(string $filepath = ''): string
{
if ($filepath) {
return static::$gameImagePath . "/{$filepath}";
}
return static::$gameImagePath;
}
public static function getImagePullURI(): string
{
$now = time();
$req_hash = Util::hashPassword(sprintf("%016x", $now), static::$imageRequestKey);
return static::$imageRequestPath . "?req={$req_hash}&time={$now}";
}
/**
* 서버 설정 반환
*
* @return \sammo\Setting[]
*/
public static function getServerList(): array{
$servKeyList = [/*_tK_serverList_*/];
$servKeyList[] = ['hwe', '훼', 'red'];
if (self::$serverList === null) {
self::$serverList = [];
foreach($servKeyList as [$servKey, $servNick, $servColor]){
self::$serverList[$servKey] = new Setting(ROOT.'/'.$servKey, $servNick, $servColor);
}
}
return self::$serverList;
}
/**
* 서버 주소 반환. 서버의 경로가 하부 디렉토리인 경우에 하부 디렉토리까지 포함
*
* @return string
*/
public static function getServerBasepath(): string
{
return self::$serverWebPath;
}
}
+1 -1
View File
@@ -38,7 +38,7 @@ $admin = getAdmin();
</tr>
<tr>
<td width=110 align=right>시작시간변경</td>
<td width=285><input type=text size=20 maxlength=20 style=color:white;background-color:black;text-align:right; name=starttime value='<?=$admin['starttime']?>'><input type=submit name=btn value=변경1></td>
<td width=285><input type=text size=20 maxlength=20 style=color:white;background-color:black;text-align:right; name=starttime value='<?=substr($admin['starttime'], 0, 19)?>'><input type=submit name=btn value=변경1></td>
<td width=110 align=right>현재도시훈사</td>
<td width=285><?=$admin['city_rate']?></td>
</tr>
+4
View File
@@ -24,3 +24,7 @@ foreach ($db->queryFirstColumn(
) as $generalNo) {
CheckHall($generalNo);
}
foreach(General::createGeneralObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc = 0')) as $genObj){
$genObj->mergeTotalInheritancePoint();
}
+11
View File
@@ -91,6 +91,7 @@ $types = [
}
return $v;
}],
["점 령", "int", function($v){$v['value'] = $v['occupied']; return $v; }],
["사 살", "int", function($v){$v['value'] = $v['killcrew']; return $v; }],
["살 상 률", "percent", function($v){
if($v['warnum'] < 10){
@@ -101,6 +102,16 @@ $types = [
}
return $v;
}],
["대 인 사 살", "int", function($v){$v['value'] = $v['killcrew_person']; return $v; }],
["대 인 살 상 률", "percent", function($v){
if($v['warnum'] < 10){
$v['value'] = 0;
}
else{
$v['value'] = $v['killcrew_person'] / max(1, $v['deathcrew_person']);
}
return $v;
}],
["보 병 숙 련 도", "int", function($v){$v['value'] = $v['dex1']; return $v; }],
["궁 병 숙 련 도", "int", function($v){$v['value'] = $v['dex2']; return $v; }],
["기 병 숙 련 도", "int", function($v){$v['value'] = $v['dex3']; return $v; }],
+215 -215
View File
@@ -1,215 +1,215 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
$type = Util::getReq('type', 'int', 9);
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
increaseRefresh("장수일람", 2);
$me = $db->queryFirstRow('SELECT con,turntime FROM general WHERE owner = %i', $userID);
$con = checkLimit($me['con']);
if ($con >= 2) {
printLimitMsg($me['turntime']);
exit();
}
if ($type <= 0 || $type > 15) {
$type = 9;
}
$ownerNameList = [];
if($gameStor->isunited){
foreach(RootDB::db()->queryAllLists('SELECT no, name FROM member') as [$ownerID, $ownerName]){
$ownerNameList[$ownerID] = $ownerName;
}
}
?>
<!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::printCSS('../e_lib/bootstrap.min.css')?>
<?=WebUtil::printCSS('../d_shared/common.css')?>
<?=WebUtil::printCSS('css/common.css')?>
<?=WebUtil::printJS('../e_lib/jquery-3.3.1.min.js')?>
<?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('../d_shared/common_path.js')?>
<?=WebUtil::printJS('js/common.js')?>
</head>
<body>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td> <br><?=closeButton()?></td></tr>
<tr><td><form name=form1 method=post>정렬순서 :
<select id='viewType' name='type' size=1>
<option value=1>국가</option>
<option value=2>통솔</option>
<option value=3>무력</option>
<option value=4>지력</option>
<option value=5>명성</option>
<option value=6>계급</option>
<option value=7>관직</option>
<option value=8>삭턴</option>
<option value=9>벌점</option>
<option value=10>Lv</option>
<option value=11>성격</option>
<option value=12>내특</option>
<option value=13>전특</option>
<option value=14>연령</option>
<option value=15>NPC</option>
</select>
<input type=submit value='정렬하기'></form>
</td></tr>
</table>
<?php
$nationname = [];
$nationlevel = [];
$nationname[0] = "-";
foreach (getAllNationStaticInfo() as $nation) {
$nationname[$nation['nation']] = $nation['name'];
$nationlevel[$nation['nation']] = $nation['level'];
}
[$orderKey, $orderDesc] = [
1=>['nation', false],
2=>['leadership', true],
3=>['strength', true],
4=>['intel', true],
5=>['experience', true],
6=>['dedication', true],
7=>['officer_level', true],
8=>['killturn', false],
9=>['connect', true],
10=>['experience', true],
11=>['personal', true],
12=>['special', true],
13=>['special2', true],
14=>['age', true],
15=>['npc', true],
][$type];
$generalList = $db->query('SELECT owner,no,picture,imgsvr,npc,age,nation,special,special2,personal,name,injury,leadership,strength,intel,experience,dedication,officer_level,killturn,connect from general order by %b %l', $orderKey, $orderDesc?'desc':'');
echo"
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td width=64 align=center id=bg1> </td>
<td width=140 align=center id=bg1> </td>
<td width=45 align=center id=bg1>연령</td>
<td width=45 align=center id=bg1>성격</td>
<td width=80 align=center id=bg1>특기</td>
<td width=45 align=center id=bg1> </td>
<td width=140 align=center id=bg1> </td>
<td width=55 align=center id=bg1> </td>
<td width=55 align=center id=bg1> </td>
<td width=75 align=center id=bg1> </td>
<td width=45 align=center id=bg1>통솔</td>
<td width=45 align=center id=bg1>무력</td>
<td width=45 align=center id=bg1>지력</td>
<td width=45 align=center id=bg1>삭턴</td>
<td width=70 align=center id=bg1>벌점</td>
</tr>";
foreach($generalList as $general){
$nation = $nationname[$general['nation']];
$lbonus = calcLeadershipBonus($general['officer_level'], $nationlevel[$general['nation']]??0);
if ($lbonus > 0) {
$lbonusText = "<font color=cyan>+{$lbonus}</font>";
} else {
$lbonusText = "";
}
if ($general['injury'] > 0) {
$leadership = intdiv($general['leadership'] * (100 - $general['injury']), 100);
$strength = intdiv($general['strength'] * (100 - $general['injury']), 100);
$intel = intdiv($general['intel'] * (100 - $general['injury']), 100);
$leadership = "<font color=red>{$leadership}</font>{$lbonusText}";
$strength = "<font color=red>{$strength}</font>";
$intel = "<font color=red>{$intel}</font>";
} else {
$leadership = "{$general['leadership']}{$lbonusText}";
$strength = "{$general['strength']}";
$intel = "{$general['intel']}";
}
if ($general['npc'] >= 2) {
$name = "<font color=cyan>{$general['name']}</font>";
} elseif ($general['npc'] == 1) {
$name = "<font color=skyblue>{$general['name']}</font>";
} else {
$name = "{$general['name']}";
}
if(key_exists($general['owner'], $ownerNameList)){
$name = $name.'<br><small>('.$ownerNameList[$general['owner']].')</small>';
}
$general['connect'] = Util::round($general['connect'], -1);
$imageTemp = GetImageURL($general['imgsvr']);
echo "
<tr data-general-id='{$general['no']}'
data-general-wounded='{$general['injury']}'
data-general-leadership='{$general['leadership']}'
data-general-leadership-bonus='{$lbonus}'
data-general-strength='{$general['strength']}'
data-general-intel='{$general['intel']}'
data-is-npc='".($general['npc']>=2?'true':'false')."'
>
<td align=center><img class='generalIcon' width='64' height='64' src='{$imageTemp}/{$general['picture']}'></img></td>
<td align=center>$name</td>
<td align=center>{$general['age']}</td>
<td align=center>".displayCharInfo($general['personal'])."</td>
<td align=center>".displaySpecialDomesticInfo($general['special'])." / ".displaySpecialWarInfo($general['special2'])."</td>
<td align=center>Lv ".getExpLevel($general['experience'])."</td>
<td align=center>{$nation}</td>
<td align=center>".getHonor($general['experience'])."</td>
<td align=center>".getDed($general['dedication'])."</td>
<td align=center>";
echo getOfficerLevelText($general['officer_level']);
echo "</td>
<td align=center>$leadership</td>
<td align=center>$strength</td>
<td align=center>$intel</td>
<td align=center>{$general['killturn']}</td>
<td align=center>{$general['connect']}";
echo "<br>【".getConnect($general['connect'])."】</td>
</tr>";
}
echo "
</table>
";
?>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td><?=closeButton()?></td></tr>
<tr><td><?=banner()?></td></tr>
</table>
<script type="text/javascript">
$(document).ready(function() {
$("#viewType").val("<?=$type?>").attr("selected", "selected");
});
</script>
</body>
</html>
<?php
namespace sammo;
include "lib.php";
include "func.php";
$type = Util::getReq('type', 'int', 9);
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
increaseRefresh("장수일람", 2);
$me = $db->queryFirstRow('SELECT con,turntime FROM general WHERE owner = %i', $userID);
$con = checkLimit($me['con']);
if ($con >= 2) {
printLimitMsg($me['turntime']);
exit();
}
if ($type <= 0 || $type > 15) {
$type = 9;
}
$ownerNameList = [];
if($gameStor->isunited){
foreach(RootDB::db()->queryAllLists('SELECT no, name FROM member') as [$ownerID, $ownerName]){
$ownerNameList[$ownerID] = $ownerName;
}
}
?>
<!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::printCSS('../e_lib/bootstrap.min.css')?>
<?=WebUtil::printCSS('../d_shared/common.css')?>
<?=WebUtil::printCSS('css/common.css')?>
<?=WebUtil::printJS('../e_lib/jquery-3.3.1.min.js')?>
<?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('../d_shared/common_path.js')?>
<?=WebUtil::printJS('js/common.js')?>
</head>
<body>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td> <br><?=closeButton()?></td></tr>
<tr><td><form name=form1 method=post>정렬순서 :
<select id='viewType' name='type' size=1>
<option value=1>국가</option>
<option value=2>통솔</option>
<option value=3>무력</option>
<option value=4>지력</option>
<option value=5>명성</option>
<option value=6>계급</option>
<option value=7>관직</option>
<option value=8>삭턴</option>
<option value=9>벌점</option>
<option value=10>Lv</option>
<option value=11>성격</option>
<option value=12>내특</option>
<option value=13>전특</option>
<option value=14>연령</option>
<option value=15>NPC</option>
</select>
<input type=submit value='정렬하기'></form>
</td></tr>
</table>
<?php
$nationname = [];
$nationlevel = [];
$nationname[0] = "-";
foreach (getAllNationStaticInfo() as $nation) {
$nationname[$nation['nation']] = $nation['name'];
$nationlevel[$nation['nation']] = $nation['level'];
}
[$orderKey, $orderDesc] = [
1=>['nation', false],
2=>['leadership', true],
3=>['strength', true],
4=>['intel', true],
5=>['experience', true],
6=>['dedication', true],
7=>['officer_level', true],
8=>['killturn', false],
9=>['connect', true],
10=>['experience', true],
11=>['personal', true],
12=>['special', true],
13=>['special2', true],
14=>['age', true],
15=>['npc', true],
][$type];
$generalList = $db->query('SELECT owner,no,picture,imgsvr,npc,age,nation,special,special2,personal,name,injury,leadership,strength,intel,experience,dedication,officer_level,killturn,connect from general order by %b %l', $orderKey, $orderDesc?'desc':'');
echo"
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td width=64 align=center id=bg1> </td>
<td width=140 align=center id=bg1> </td>
<td width=45 align=center id=bg1>연령</td>
<td width=45 align=center id=bg1>성격</td>
<td width=80 align=center id=bg1>특기</td>
<td width=45 align=center id=bg1> </td>
<td width=140 align=center id=bg1> </td>
<td width=55 align=center id=bg1> </td>
<td width=55 align=center id=bg1> </td>
<td width=75 align=center id=bg1> </td>
<td width=45 align=center id=bg1>통솔</td>
<td width=45 align=center id=bg1>무력</td>
<td width=45 align=center id=bg1>지력</td>
<td width=45 align=center id=bg1>삭턴</td>
<td width=70 align=center id=bg1>벌점</td>
</tr>";
foreach($generalList as $general){
$nation = $nationname[$general['nation']];
$lbonus = calcLeadershipBonus($general['officer_level'], $nationlevel[$general['nation']]??0);
if ($lbonus > 0) {
$lbonusText = "<font color=cyan>+{$lbonus}</font>";
} else {
$lbonusText = "";
}
if ($general['injury'] > 0) {
$leadership = intdiv($general['leadership'] * (100 - $general['injury']), 100);
$strength = intdiv($general['strength'] * (100 - $general['injury']), 100);
$intel = intdiv($general['intel'] * (100 - $general['injury']), 100);
$leadership = "<font color=red>{$leadership}</font>{$lbonusText}";
$strength = "<font color=red>{$strength}</font>";
$intel = "<font color=red>{$intel}</font>";
} else {
$leadership = "{$general['leadership']}{$lbonusText}";
$strength = "{$general['strength']}";
$intel = "{$general['intel']}";
}
if ($general['npc'] >= 2) {
$name = "<font color=cyan>{$general['name']}</font>";
} elseif ($general['npc'] == 1) {
$name = "<font color=skyblue>{$general['name']}</font>";
} else {
$name = "{$general['name']}";
}
if(key_exists($general['owner'], $ownerNameList)){
$name = $name.'<br><small>('.$ownerNameList[$general['owner']].')</small>';
}
$general['connect'] = Util::round($general['connect'], -1);
$imageTemp = GetImageURL($general['imgsvr']);
echo "
<tr data-general-id='{$general['no']}'
data-general-wounded='{$general['injury']}'
data-general-leadership='{$general['leadership']}'
data-general-leadership-bonus='{$lbonus}'
data-general-strength='{$general['strength']}'
data-general-intel='{$general['intel']}'
data-is-npc='".($general['npc']>=2?'true':'false')."'
>
<td align=center><img class='generalIcon' width='64' height='64' src='{$imageTemp}/{$general['picture']}'></img></td>
<td align=center>$name</td>
<td align=center>{$general['age']}</td>
<td align=center>".displayCharInfo($general['personal'])."</td>
<td align=center>".displaySpecialDomesticInfo($general['special'])." / ".displaySpecialWarInfo($general['special2'])."</td>
<td align=center>Lv ".getExpLevel($general['experience'])."</td>
<td align=center>{$nation}</td>
<td align=center>".getHonor($general['experience'])."</td>
<td align=center>".getDed($general['dedication'])."</td>
<td align=center>";
echo getOfficerLevelText($general['officer_level']);
echo "</td>
<td align=center>$leadership</td>
<td align=center>$strength</td>
<td align=center>$intel</td>
<td align=center>{$general['killturn']}</td>
<td align=center>{$general['connect']}";
echo "<br>【".getConnect($general['connect'])."】</td>
</tr>";
}
echo "
</table>
";
?>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td><?=closeButton()?></td></tr>
<tr><td><?=banner()?></td></tr>
</table>
<script type="text/javascript">
$(document).ready(function() {
$("#viewType").val("<?=$type?>").attr("selected", "selected");
});
</script>
</body>
</html>
+3
View File
@@ -90,8 +90,11 @@ $types = [
'warnum'=>['전 투 횟 수', 'int'],
'killnum'=>['승 리', 'int'],
'winrate'=>['승 률', 'percent'],
'occupied'=>['점 령', 'int'],
'killcrew'=>['사 살', 'int'],
'killrate'=>['살 상 률', 'percent'],
'killcrew_person'=>['대 인 사 살', 'int'],
'killrate_person'=>['대 인 살 상 률', 'percent'],
'dex1'=>['보 병 숙 련 도', 'int'],
'dex2'=>['궁 병 숙 련 도', 'int'],
'dex3'=>['기 병 숙 련 도', 'int'],
+6 -1
View File
@@ -59,8 +59,13 @@ foreach (getAllNationStaticInfo() as $nation) {
$nationName[$nation['nation']] = $nation['name'];
}
$generalList = $db->query('SELECT npc,nation,name,owner_name,special,special2,personal,leadership,strength,intel,leadership+strength+intel as sum,explevel,experience,dedication from general where npc=1');
$generalListFromPool = $db->query('SELECT npc,nation,name,owner_name,special,special2,personal,leadership,strength,intel,leadership+strength+intel as sum,explevel,experience,dedication from general JOIN select_pool on general.no = select_pool.general_id where npc=0');
if($generalListFromPool){
$generalList = array_merge($generalListFromPool, $generalList);
}
$sortType = [
1 => ['name', true],
2 => ['nation', true],
+1 -1
View File
@@ -72,7 +72,7 @@ var maxChiefTurn = <?=GameConst::$maxChiefTurn?>;
></div
><div
><?=chiefCommandTable($generalObj)
?><input type='button' id='setCommand' style='visibility:hidden;background-color:<?=GameConst::$basecolor2?>;color:white;font-size:13px;' value='실 행'
?><br><input type='button' id='setCommand' style='visibility:hidden;background-color:<?=GameConst::$basecolor2?>;color:white;font-size:13px;' value='실 행'
></div
></div
></div
+65 -11
View File
@@ -148,8 +148,31 @@ echo "
unset($city);
// 첩보된 도시까지만 허용
if($valid == 0 && $userGrade < 5) {
$showDetailedInfo = false;
if($valid){
$showDetailedInfo = true;
}
if(!key_exists($citylist, CityConst::all())){
$citylist = $me['city'];
$showDetailedInfo = true;
$valid = 1;
}
if($userGrade >= 5){
$valid = true;
$showDetailedInfo = true;
}
if(!$valid) {
$ownCities = Util::convertArrayToSetLike($db->queryFirstColumn('SELECT city FROM city WHERE nation = %i AND nation != 0', $me['nation']));
foreach(array_keys(CityConst::byID($citylist)->path) as $pathID){
if(key_exists($pathID, $ownCities)){
$showDetailedInfo = true;
break;
}
}
}
@@ -172,11 +195,35 @@ if($city['trade'] === null) {
}
$dbColumns = General::mergeQueryColumn(['npc', 'defence_train', 'no', 'picture', 'imgsvr', 'name', 'injury', 'leadership', 'strength', 'intel', 'officer_level', 'nation', 'crewtype', 'crew', 'train', 'atmos'], 2)[0];
$generals = $db->query(
'SELECT %l from general where city=%i order by name',
Util::formatListOfBackticks($dbColumns),
$city['city']
);
if($showDetailedInfo){
$generals = $db->query(
'SELECT %l from general where city=%i order by turntime',
Util::formatListOfBackticks($dbColumns),
$city['city']
);
}
else{
$generals = [];
}
if($valid){
$city['trustText'] = round($city['trust'], 1);
$city['popRateText'] = round($city['pop']/$city['pop_max']*100, 2);
}
else{
$city['agri'] = '?';
$city['comm'] = '?';
$city['pop'] = '?';
$city['secu'] = '?';
$city['trustText'] = '?';
$city['popRateText'] = '?';
if($city['nation'] != 0){
$city['def'] = '?';
$city['wall'] = '?';
}
}
$generalTurnList = [];
@@ -257,6 +304,10 @@ foreach($generals as $general){
$crew = $general['crew'];
$train = -1;
$atmos = -1;
if(!$valid){
$crew = -1;
}
}
$nation = $general['nation'];
@@ -331,7 +382,9 @@ foreach($generalsFormat as $general){
}
if($general['nation'] != $myNation['nation']){
$enemyCnt += 1;
$enemyCrew += $general['crew'];
if($general['crew'] >= 0){
$enemyCrew += $general['crew'];
}
if($general['crew'] > 0){
$enemyArmedCnt += 1;
}
@@ -402,11 +455,11 @@ foreach($generalsFormat as $general){
</tr>
<tr>
<td align=center class=bg1>민심</td>
<td align=center><?=round($city['trust'], 1)?></td>
<td align=center><?=$city['trustText']?></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><?=$city['popRateText']?>%</td>
<td align=center class=bg1>태수</td>
<td align=center><?=$officer[4]['name']?></td>
<td align=center class=bg1>군사</td>
@@ -430,11 +483,12 @@ foreach($generalsFormat as $general){
</tr>
<tr>
<td align=center class=bg1>장수</td>
<td colspan=11><?=join(', ', $generalsName)?></td>
<td colspan=11><?=$showDetailedInfo?join(', ', $generalsName):'<span style="color:gray">알 수 없음</span>'?></td>
</tr>
</table>
<br>
<?php if($showDetailedInfo): ?>
<table align=center class='tb_layout bg0'>
<thead>
<tr>
@@ -459,7 +513,7 @@ foreach($generalsFormat as $general){
?>
</tbody>
</table>
<?php endif; ?>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td><?=backButton()?></td></tr>
<tr><td><?=banner()?> </td></tr>
+1 -1
View File
@@ -93,7 +93,7 @@ switch ($type) {
case 5: $orderSQL = "order by crew desc"; break;
case 6: $orderSQL = "order by killturn"; break;
case 7: $orderSQL = "order by turntime"; break;
case 8: $orderSQL = "order by troop_leader desc"; break;
case 8: $orderSQL = "order by troop desc"; break;
}
$generals = $db->query(
+131
View File
@@ -0,0 +1,131 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$generalID = $session->generalID;
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$me = General::createGeneralObjFromDB($generalID);
$pointHelpText = [
'sum' => '다음 플레이에서 사용할 수 있는 총 포인트입니다.',
'new' => '이번 플레이에서 얻은 총 포인트입니다.',
'previous' => '이전에 물려받은 포인트입니다.',
'lived_month' => '살아남은 기간입니다. (1개월 단위)',
'max_belong' => '가장 오래 임관했던 국가의 연도입니다.',
'max_domestic_critical' => '성공한 내정 중 최대 연속값입니다.',
'snipe_combat' => '유리한 상성을 가지고 전투했습니다.',
'combat' => '전투 횟수입니다.',
'sabotage' => '계략 성공 횟수입니다.',
'unifier' => '천통에 기여한 포인트입니다. <br>각 국의 군주, 천통 수뇌, 천통 군주가 받습니다.',
'dex' => '총 숙련도합입니다.',
'tournament' => '토너먼트 입상 포인트입니다.',
'betting' => '성공적인 베팅을 했습니다. <br>수익율과 베팅 성공 횟수를 따릅니다.',
];
$items = [];
foreach(array_keys(General::INHERITANCE_KEY) as $key){
$items[$key] = $me->getInheritancePoint($key)??0;
}
?>
<!DOCTYPE html>
<html>
<head>
<title><?= UniqueConst::$serverName ?>: 유산 관리</title>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<?= WebUtil::printCSS('../e_lib/bootstrap.min.css') ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<?= WebUtil::printCSS('../css/config.css') ?>
<?= WebUtil::printCSS('css/common.css') ?>
<?= WebUtil::printCSS('css/inheritPoint.css') ?>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printJS('../e_lib/jquery-3.3.1.min.js') ?>
<?= WebUtil::printJS('../e_lib/bootstrap.bundle.min.js') ?>
<?= WebUtil::printJS('js/common.js') ?>
<?= WebUtil::printJS('js/inheritPoint.js') ?>
<script>
var items = <?=Json::encode($items)?>;
var helpText = <?=Json::encode($pointHelpText)?>;
</script>
</head>
<body onload="formStart()">
<table style='width:1000px;margin:auto;' class='tb_layout bg0'>
<tr>
<td style='text-align:left;'>유산 관리<br><?= backButton() ?></td>
</tr>
</table>
<div id="container" class="tb_layout bg0" style="width:1000px;margin:auto;border:solid 1px #888888;">
<div id='inheritance_list'>
<div id="inherit_sum" class='inherit_item'>
<div class="row">
<label id="inherit_sum_head" class='inherit_head col-sm-6 col-form-label'> 포인트</label>
<div class="col-sm-6">
<input type="text" class="form-control inherit_value" readonly id="inherit_sum_value" value="">
</div>
</div>
<div style="text-align:right">
<small class="form-text text-muted"></small>
</div>
</div>
<div id="inherit_previous" class='inherit_item'>
<div class="row">
<label id="inherit_sum_head" class='inherit_head col-sm-6 col-form-label'>기존 포인트</label>
<div class="col-sm-6">
<input type="text" class="form-control inherit_value" readonly id="inherit_previous_value" value="">
</div>
</div>
<div style="text-align:right">
<small class="form-text text-muted"></small>
</div>
</div>
<div id="inherit_new" class='inherit_item'>
<div class="row">
<label id="inherit_sum_head" class='inherit_head col-sm-6 col-form-label'>신규 포인트</label>
<div class="col-sm-6">
<input type="text" class="form-control inherit_value" readonly id="inherit_new_value" value="">
</div>
</div>
<div style="text-align:right">
<small class="form-text text-muted"></small>
</div>
</div>
<div style="width:100%; padding:0 10px"><hr style="border-top:1px solid #888888;"></div>
<?php foreach (General::INHERITANCE_KEY as $key => [$type, $multiplier, $name]) : ?>
<?php if ($key == 'previous') {
continue;
} ?>
<div id="inherit_<?= $key ?>" class='inherit_item inherit_template_item'>
<div class="row">
<label id="inherit_<?= $key ?>_head" class='inherit_head col-sm-6 col-form-label'><?= $name ?></label>
<div class="col-sm-6">
<input type="text" class="form-control inherit_value" readonly id="inherit_<?= $key ?>_value" value="">
</div>
</div>
<div style="text-align:right">
<small class="form-text text-muted"></small>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</body>
</html>
+527 -527
View File
@@ -1,527 +1,527 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
increaseRefresh("인사부", 1);
//훼섭 추방을 위해 갱신
TurnExecutionHelper::executeAllCommand();
$me = $db->queryFirstRow('SELECT no,nation,officer_level from general where owner=%i', $userID);
$nationID = $me['nation'];
$meLevel = $me['officer_level'];
if($meLevel == 0) {
echo "재야입니다.";
exit();
}
$nation = $db->queryFirstRow('SELECT nation,name,level,color,chief_set from nation where nation=%i', $nationID); //국가정보
?>
<!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('../e_lib/jquery-3.3.1.min.js')?>
<?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('../e_lib/select2/select2.full.min.js')?>
<?=WebUtil::printJS('js/common.js')?>
<?=WebUtil::printJS('js/bossInfo.js')?>
<?=WebUtil::printCSS('../e_lib/bootstrap.min.css')?>
<?=WebUtil::printCSS('../e_lib/select2/select2.min.css')?>
<?=WebUtil::printCSS('../e_lib/select2/select2-bootstrap4.css')?>
<?=WebUtil::printCSS('../d_shared/common.css')?>
<?=WebUtil::printCSS('css/common.css')?>
<script type="text/javascript">
var chiefStatMin = <?=GameConst::$chiefStatMin?>;
var myLevel = <?=$meLevel?>;
</script>
<?php
$ambassadors = $db->query('SELECT no, name, officer_level, penalty, permission FROM general WHERE permission = \'ambassador\' AND nation = %i', $nationID);
$auditors = $db->query('SELECT no, name, officer_level, penalty, permission FROM general WHERE permission = \'auditor\' AND nation = %i', $nationID);
$candidateAmbassadors = [];
$candidateAuditors = [];
foreach($ambassadors as $ambassador){
$candidateAmbassadors[] = $ambassador;
}
foreach($auditors as $auditor){
$candidateAuditors[] = $auditor;
}
foreach($db->query('SELECT no, name, nation, officer_level, penalty, permission FROM general WHERE nation = %i AND permission = \'normal\' AND officer_level != 12', $nationID) as $candidate){
$maxPermission = checkSecretMaxPermission($candidate);
if($maxPermission == 4){
$candidateAmbassadors[] = $candidate;
}
if($maxPermission >= 3){
$candidateAuditors[] = $candidate;
}
}
?>
<script>
var candidateAmbassadors = <?=Json::encode(array_map(function($value){
return [
'id'=>$value['no'],
'text'=>$value['name'],
"selected"=>($value['permission']!='normal')
];
}, $candidateAmbassadors))?>;
var candidateAuditors = <?=Json::encode(array_map(function($value){
return [
'id'=>$value['no'],
'text'=>$value['name'],
"selected"=>($value['permission']!='normal')
];
}, $candidateAuditors))?>;
</script>
</head>
<body>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td> <br><?=backButton()?></td></tr>
</table>
<br>
<?php
$lv = getNationChiefLevel($nation['level']);
if($meLevel >= 5) { $btn = "button"; }
else { $btn = "hidden"; }
$level = Util::convertArrayToDict(
$db->query(
'SELECT name,officer_level,city,picture,imgsvr,belong from general where nation=%i and officer_level>=%i order by officer_level desc',
$nationID, $lv
),
'officer_level'
);
$tigers = $db->query('SELECT value, name
FROM rank_data LEFT JOIN general ON rank_data.general_id = general.no
WHERE rank_data.nation_id = %i AND rank_data.type = "warnum" AND value > 0 ORDER BY value DESC LIMIT 5',
$nationID
);// 오호장군
$tigerstr = join(', ', array_map(function($arr){
$number = number_format($arr['value']);
return "{$arr['name']}{$number}";
}, $tigers));
$eagles = $db->query('SELECT value, name
FROM rank_data LEFT JOIN general ON rank_data.general_id = general.no
WHERE rank_data.nation_id = %i AND rank_data.type = "firenum" AND value > 0 ORDER BY value DESC LIMIT 7',
$nationID
);// 건안칠자
$eaglestr = join(', ', array_map(function($arr){
$number = number_format($arr['value']);
return "{$arr['name']}{$number}";
}, $eagles));
?>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td align=center style='color:<?=newColor($nation['color'])?>; background-color:<?=$nation['color']?>' colspan=6>
<font size=5> <?=$nation['name']?> 】</font>
</td>
</tr>
<?php
for($i=12; $i >= $lv; $i-=2) {
$i1 = $i; $i2 = $i - 1;
$imageTemp1 = GetImageURL($level[$i1]['imgsvr']??0);
$imageTemp2 = GetImageURL($level[$i2]['imgsvr']??0);
?>
<tr>
<td width=98 align=center id=bg1><font size=4><?=getOfficerLevelText($i1, $nation['level'])?></font></td>
<td width=64 class='generalIcon' height=64 style='background:no-repeat center url("<?=$imageTemp1?>/<?=$level[$i1]['picture']??'default.jpg'?>");background-size:64px;'></td>
<td width=332><font size=4><?=$level[$i1]['name']??'-'?>(<?=$level[$i1]['belong']??'-'?>년)</font></td>
<td width=98 align=center id=bg1><font size=4><?=getOfficerLevelText($i2, $nation['level'])?></font></td>
<td width=64 class='generalIcon' height=64 style='background:no-repeat center url("<?=$imageTemp2?>/<?=$level[$i2]['picture']??'default.jpg'?>");background-size:64px;'></td>
<td width=332><font size=4><?=$level[$i2]['name']??'-'?>(<?=$level[$i2]['belong']??'-'?>년)</font></td>
</tr>
<?php
}
?>
<tr>
<td width=98 align=center id=bg1>오호장군【승전】</td>
<td colspan=5><?=$tigerstr?></td>
</tr>
<tr>
<td width=98 align=center id=bg1>건안칠자【계략】</td>
<td colspan=5><?=$eaglestr?></td>
</tr>
</table>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td colspan=6 height=5></td></tr>
<tr><td colspan=2 align=center bgcolor=red> </td></tr>
<tr>
<td width=498 align=right id=bg1>대상 장수</td>
<td width=498>
<?php
if($meLevel >= 5){
$candidateStrength = $db->query('SELECT no,name,officer_level,city,npc from general where nation=%i and officer_level!=12 and strength>=%i order by npc,binary(name)', $nationID, GameConst::$chiefStatMin);
$candidateIntel = $db->query('SELECT no,name,officer_level,city,npc from general where nation=%i and officer_level!=12 and intel>=%i order by npc,binary(name)', $nationID, GameConst::$chiefStatMin);
$candidateAny = $db->query('SELECT no,name,officer_level,city,npc,leadership,strength,intel,killturn from general where nation=%i and officer_level!=12 order by npc,binary(name)', $nationID); //추방 때문에 조금 더 김
}
else{
$candidateStrength = [];
$candidateIntel = [];
$candidateAny = [];
}
if($meLevel >= 5 && !isOfficerSet($nation['chief_set'], $meLevel)) {
echo "
<select id='genlist_kick' size=1 style=color:white;background-color:black;>";
foreach($candidateAny as $general) {
if($general['no'] === $me['no']){
continue;
}
echo "
<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']} <small>({$general['leadership']}/{$general['strength']}/{$general['intel']}, {$general['killturn']})</small></option>";
}
echo "
</select>
<input type=$btn id='btn_kick' value=추방>";
}
$officerLevelText = getOfficerLevelText(11, $nation['level']);
echo "
</td>
</tr>
</table>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td colspan=4 height=5></td></tr>
<tr><td colspan=4 align=center bgcolor=blue> </td></tr>
<tr>
<td width=98 align=right id=bg1>".getOfficerLevelText(12, $nation['level'])."</td>
<td width=398>{$level[12]['name']} ".CityConst::byID($level[12]['city'])->name."</td>
<td width=98 align=right id=bg1>{$officerLevelText}</td>
<td width=398>
";
if($meLevel >= 5 && !isOfficerSet($nation['chief_set'], 11)) {
echo "
<select id='genlist_11' size=1 maxlength=15 style=color:white;background-color:black;>
<option value=0 data-officer_level='0' data-name=''>____공석____</option>";
foreach($candidateAny as $general) {
if($general['officer_level'] == 11) {
echo "<option style=color:red; selected data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} elseif($general['officer_level'] > 1) {
echo "<option style=color:orange; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} else {
echo "<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
}
}
echo "
</select>
<input class='btn_appoint' type=$btn data-officer_level='11' data-officer_level_text='{$officerLevelText}' value=임명>";
} else {
if(key_exists(11, $level)){
echo "{$level[11]['name']}".CityConst::byID($level[11]['city'])->name."";
}
}
echo "
</td>
</tr>
";
for($i=10; $i >= $lv; $i--) {
if($i % 2 == 0) { echo "<tr>"; }
$officerLevelText = getOfficerLevelText($i, $nation['level']);
echo "
<td width=98 align=right id=bg1>{$officerLevelText}</td>
<td width=398>
";
if($meLevel >= 5 && !isOfficerSet($nation['chief_set'], $i)) {
echo "
<select id='genlist_{$i}' size=1 style=color:white;background-color:black;>
<option value=0 data-officer_level='0' data-name=''>____공석____</option>";
foreach(($i%2==0?$candidateStrength:$candidateIntel) as $general) {
if($general['officer_level'] == $i) {
echo "<option style=color:red; selected data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} elseif($general['officer_level'] > 1) {
echo "<option style=color:orange; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} else {
echo "<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
}
}
echo "
</select>
<input class='btn_appoint' type=$btn data-officer_level='{$i}' data-officer_level_text='$officerLevelText' value=임명>";
} else {
$general = $level[$i]??null;
if($general){
echo "{$general['name']}".CityConst::byID($general['city'])->name."";
}
}
echo "</td>";
if($i % 2 == 1) { echo "</tr>"; }
}
echo "
<tr><td colspan=4> <font color=red>빨간색</font> 현재 임명중인 장수, <font color=orange>노란색</font> 다른 관직에 임명된 장수, 하얀색은 일반 장수를 뜻합니다.</td></tr>
</table>
";
if($meLevel == 12):
?>
<table align='center' width='1000' class='tb_layout bg0'>
<tr><td colspan='4' height='5'></td></tr>
<tr><td colspan='4' align='center' bgcolor='purple'> </td></tr>
<tr>
<td width=98 align=right id=bg1>외교권자</td>
<td width=398>
<select id="selectAmbassador" multiple="multiple">
</select>
<button id='changeAmbassador' type='button'>임명</button>
</td>
<td width=98 align=right id=bg1>조언자</td>
<td width=398>
<select id="selectAuditor" multiple="multiple">
</select>
<button id='changeAuditor' type='button'>임명</button>
</td>
</tr>
</table>
<?php
endif;
?>
<table align=center width=1000 id='officer_list' class='tb_layout bg0'>
<tr><td colspan=5 height=5></td></tr>
<?php
if($meLevel >= 5) {
$officerLevelText = getOfficerLevelText(4, $nation['level']);
echo "
<tr><td colspan=5 align=center bgcolor=orange> </td></tr>
<tr>
<td colspan=3 align=right id=bg2>{$officerLevelText} 임명</td>
<td colspan=2>
<select id='citylist_4' size=1 style=color:white;background-color:black;>
";
$cityList = $db->query('SELECT city,name,region,officer_set FROM city WHERE nation=%i ORDER BY region,level DESC,binary(name)', $nationID);
$region = 0;
foreach($cityList as $city){
if(isOfficerSet($city['officer_set'], 4)){
continue;
}
if($region != $city['region']) {
if($region != 0) {
echo "</optgroup>";
}
echo "<optgroup label=' 【 ".CityConst::$regionMap[$city['region']]." 】 ' style=color:skyblue;>";
$region = $city['region'];
}
echo "<option value='{$city['city']}' style=color:white;><span class='name_field'>{$city['name']}</span></option>";
}
echo "</optgroup>";
echo "
</select>
<select id='genlist_4' size=1 style=color:white;background-color:black;>
<option value=0 data-officer_level='0' data-name=''>____공석____</option>
";
foreach($candidateStrength as $general) {
if($general['officer_level'] == 4) {
echo "<option style=color:red; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} elseif($general['officer_level'] > 1) {
echo "<option style=color:orange; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} else {
echo "<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
}
}
echo "
</select>
<input class='btn_appoint' type=$btn data-officer_level='4' data-officer_level_text='{$officerLevelText}' value=임명>
</td>
</tr>";
$officerLevelText = getOfficerLevelText(3, $nation['level']);
echo "<tr>
<td colspan=3 align=right id=bg2>{$officerLevelText} 임명</td>
<td colspan=2>
<select id='citylist_3' size=1 style=color:white;background-color:black;>
";
$region = 0;
foreach($cityList as $city){
if(isOfficerSet($city['officer_set'], 3)){
continue;
}
if($region != $city['region']) {
if($region != 0) {
echo "</optgroup>";
}
echo "<optgroup label=' 【 ".CityConst::$regionMap[$city['region']]." 】 ' style=color:skyblue;>";
$region = $city['region'];
}
echo "<option value='{$city['city']}' style=color:white;><span class='name_field'>{$city['name']}</span></option>";
}
echo "</optgroup>";
echo "
</select>
<select id='genlist_3' size=1 style=color:white;background-color:black;>
<option value=0 data-officer_level='0' data-name=''>____공석____</option>
";
foreach($candidateIntel as $general) {
if($general['officer_level'] == 3) {
echo "<option style=color:red; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} elseif($general['officer_level'] > 1) {
echo "<option style=color:orange; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} else {
echo "<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
}
}
echo "
</select>
<input class='btn_appoint' type=$btn data-officer_level='3' data-officer_level_text='{$officerLevelText}' value=임명>
</td>
</tr>";
$officerLevelText = getOfficerLevelText(2, $nation['level']);
echo "<tr>
<td colspan=3 align=right id=bg2>{$officerLevelText} 임명</td>
<td colspan=2>
<select id='citylist_2' size=1 style=color:white;background-color:black;>
";
$region = 0;
foreach($cityList as $city){
if(isOfficerSet($city['officer_set'], 2)){
continue;
}
if($region != $city['region']) {
if($region != 0) {
echo "</optgroup>";
}
echo "<optgroup label=' 【 ".CityConst::$regionMap[$city['region']]." 】 ' style=color:skyblue;>";
$region = $city['region'];
}
echo "<option value='{$city['city']}' style=color:white;><span class='name_field'>{$city['name']}</span></option>";
}
echo "</optgroup>";
echo "
</select>
<select id='genlist_2' size=1 style=color:white;background-color:black;>
<option value=0>____<span class='name_field'>공석</span>____</option>
";
foreach ($candidateAny as $general) {
if($general['officer_level'] == 2) {
echo "<option style=color:red; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} elseif($general['officer_level'] > 1) {
echo "<option style=color:orange; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} else {
echo "<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
}
}
echo "
</select>
<input class='btn_appoint' type=$btn data-officer_level='2' data-officer_level_text='{$officerLevelText}' value=임명>
</td>
</tr>
<tr><td colspan=5> <font color=red>빨간색</font> 현재 임명중인 장수, <font color=orange>노란색</font> 다른 관직에 임명된 장수, 하얀색은 일반 장수를 뜻합니다.</td></tr>
";
}
echo "
<tr>
<td width=158 align=center id=bg1 colspan=2><font size=4> </font></td>
<td width=278 align=center id=bg1><font size=4> (사관) 【현재도시】</font></td>
<td width=278 align=center id=bg1><font size=4> (사관) 【현재도시】</font></td>
<td width=278 align=center id=bg1><font size=4> (사관) 【현재도시】</font></td>
</tr>
";
$citylevel = getCityLevelList();
$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){
$officerCityID = $officer['officer_city'];
if(!key_exists($officerCityID, $officerList)){
$officerList[$officerCityID] = [];
}
$officerList[$officerCityID][$officer['officer_level']] = $officer;
}
$region = 0;
$dummyOfficer = [
'name'=>'-',
'belong'=>0,
];
$textColor = newColor($nation['color']);
$nationColor = $nation['color'];
foreach($db->query('SELECT city,name,level,region,officer_set from city where nation=%i order by region,level desc,binary(name)', $nationID) as $city) {
$cityID = $city['city'];
$cityOfficerList = $officerList[$cityID]??[];
?>
<?php if($region != $city['region']): ?>
<tr><td colspan=5 height=3 id=bg1></td></tr>
<tr><td colspan=5 id=bg1><font size=4 color=skyblue> <?=CityConst::$regionMap[$city['region']]?> 】 </font></td></tr>
<?php endif; $region = $city['region']; ?>
<tr>
<td width=78 align=center style='color:<?=$textColor?>;background-color:<?=$nationColor?>;font-size:1.2em;'><?=$citylevel[$city['level']]?>】</td>
<td width=78 align=right style='color:<?=$textColor?>;background-color:<?=$nationColor?>;font-size:1.2em;'><?=$city['name']?>&nbsp;&nbsp;</td>
<?php foreach(Util::range(4, 1, -1) as $officerLevel): ?>
<?php if(key_exists($officerLevel, $cityOfficerList)):
$officer = $cityOfficerList[$officerLevel];
?>
<td><?=$officer['name']?>(<?=$officer['belong']?>년) 【<?=CityConst::byID($officer['city'])->name?>】</td>
<?php else: ?>
<td>-</td>
<?php endif; ?>
<?php endforeach; ?>
</tr>
<?php
}
?>
<tr><td colspan=5> <font color=orange>노란색</font> 변경 불가능, 하얀색은 변경 가능 관직입니다.</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>
<?php
namespace sammo;
include "lib.php";
include "func.php";
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
increaseRefresh("인사부", 1);
//훼섭 추방을 위해 갱신
TurnExecutionHelper::executeAllCommand();
$me = $db->queryFirstRow('SELECT no,nation,officer_level from general where owner=%i', $userID);
$nationID = $me['nation'];
$meLevel = $me['officer_level'];
if($meLevel == 0) {
echo "재야입니다.";
exit();
}
$nation = $db->queryFirstRow('SELECT nation,name,level,color,chief_set from nation where nation=%i', $nationID); //국가정보
?>
<!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('../e_lib/jquery-3.3.1.min.js')?>
<?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('../e_lib/select2/select2.full.min.js')?>
<?=WebUtil::printJS('js/common.js')?>
<?=WebUtil::printJS('js/bossInfo.js')?>
<?=WebUtil::printCSS('../e_lib/bootstrap.min.css')?>
<?=WebUtil::printCSS('../e_lib/select2/select2.min.css')?>
<?=WebUtil::printCSS('../e_lib/select2/select2-bootstrap4.css')?>
<?=WebUtil::printCSS('../d_shared/common.css')?>
<?=WebUtil::printCSS('css/common.css')?>
<script type="text/javascript">
var chiefStatMin = <?=GameConst::$chiefStatMin?>;
var myLevel = <?=$meLevel?>;
</script>
<?php
$ambassadors = $db->query('SELECT no, name, officer_level, penalty, permission FROM general WHERE permission = \'ambassador\' AND nation = %i', $nationID);
$auditors = $db->query('SELECT no, name, officer_level, penalty, permission FROM general WHERE permission = \'auditor\' AND nation = %i', $nationID);
$candidateAmbassadors = [];
$candidateAuditors = [];
foreach($ambassadors as $ambassador){
$candidateAmbassadors[] = $ambassador;
}
foreach($auditors as $auditor){
$candidateAuditors[] = $auditor;
}
foreach($db->query('SELECT no, name, nation, officer_level, penalty, permission FROM general WHERE nation = %i AND permission = \'normal\' AND officer_level != 12', $nationID) as $candidate){
$maxPermission = checkSecretMaxPermission($candidate);
if($maxPermission == 4){
$candidateAmbassadors[] = $candidate;
}
if($maxPermission >= 3){
$candidateAuditors[] = $candidate;
}
}
?>
<script>
var candidateAmbassadors = <?=Json::encode(array_map(function($value){
return [
'id'=>$value['no'],
'text'=>$value['name'],
"selected"=>($value['permission']!='normal')
];
}, $candidateAmbassadors))?>;
var candidateAuditors = <?=Json::encode(array_map(function($value){
return [
'id'=>$value['no'],
'text'=>$value['name'],
"selected"=>($value['permission']!='normal')
];
}, $candidateAuditors))?>;
</script>
</head>
<body>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td> <br><?=backButton()?></td></tr>
</table>
<br>
<?php
$lv = getNationChiefLevel($nation['level']);
if($meLevel >= 5) { $btn = "button"; }
else { $btn = "hidden"; }
$level = Util::convertArrayToDict(
$db->query(
'SELECT name,officer_level,city,picture,imgsvr,belong from general where nation=%i and officer_level>=%i order by officer_level desc',
$nationID, $lv
),
'officer_level'
);
$tigers = $db->query('SELECT value, name
FROM rank_data LEFT JOIN general ON rank_data.general_id = general.no
WHERE rank_data.nation_id = %i AND rank_data.type = "killnum" AND value > 0 ORDER BY value DESC LIMIT 5',
$nationID
);// 오호장군
$tigerstr = join(', ', array_map(function($arr){
$number = number_format($arr['value']);
return "{$arr['name']}{$number}";
}, $tigers));
$eagles = $db->query('SELECT value, name
FROM rank_data LEFT JOIN general ON rank_data.general_id = general.no
WHERE rank_data.nation_id = %i AND rank_data.type = "firenum" AND value > 0 ORDER BY value DESC LIMIT 7',
$nationID
);// 건안칠자
$eaglestr = join(', ', array_map(function($arr){
$number = number_format($arr['value']);
return "{$arr['name']}{$number}";
}, $eagles));
?>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td align=center style='color:<?=newColor($nation['color'])?>; background-color:<?=$nation['color']?>' colspan=6>
<font size=5> <?=$nation['name']?> 】</font>
</td>
</tr>
<?php
for($i=12; $i >= $lv; $i-=2) {
$i1 = $i; $i2 = $i - 1;
$imageTemp1 = GetImageURL($level[$i1]['imgsvr']??0);
$imageTemp2 = GetImageURL($level[$i2]['imgsvr']??0);
?>
<tr>
<td width=98 align=center id=bg1><font size=4><?=getOfficerLevelText($i1, $nation['level'])?></font></td>
<td width=64 class='generalIcon' height=64 style='background:no-repeat center url("<?=$imageTemp1?>/<?=$level[$i1]['picture']??'default.jpg'?>");background-size:64px;'></td>
<td width=332><font size=4><?=$level[$i1]['name']??'-'?>(<?=$level[$i1]['belong']??'-'?>년)</font></td>
<td width=98 align=center id=bg1><font size=4><?=getOfficerLevelText($i2, $nation['level'])?></font></td>
<td width=64 class='generalIcon' height=64 style='background:no-repeat center url("<?=$imageTemp2?>/<?=$level[$i2]['picture']??'default.jpg'?>");background-size:64px;'></td>
<td width=332><font size=4><?=$level[$i2]['name']??'-'?>(<?=$level[$i2]['belong']??'-'?>년)</font></td>
</tr>
<?php
}
?>
<tr>
<td width=98 align=center id=bg1>오호장군【승전】</td>
<td colspan=5><?=$tigerstr?></td>
</tr>
<tr>
<td width=98 align=center id=bg1>건안칠자【계략】</td>
<td colspan=5><?=$eaglestr?></td>
</tr>
</table>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td colspan=6 height=5></td></tr>
<tr><td colspan=2 align=center bgcolor=red> </td></tr>
<tr>
<td width=498 align=right id=bg1>대상 장수</td>
<td width=498>
<?php
if($meLevel >= 5){
$candidateStrength = $db->query('SELECT no,name,officer_level,city,npc from general where nation=%i and officer_level!=12 and strength>=%i order by npc,binary(name)', $nationID, GameConst::$chiefStatMin);
$candidateIntel = $db->query('SELECT no,name,officer_level,city,npc from general where nation=%i and officer_level!=12 and intel>=%i order by npc,binary(name)', $nationID, GameConst::$chiefStatMin);
$candidateAny = $db->query('SELECT no,name,officer_level,city,npc,leadership,strength,intel,killturn from general where nation=%i and officer_level!=12 order by npc,binary(name)', $nationID); //추방 때문에 조금 더 김
}
else{
$candidateStrength = [];
$candidateIntel = [];
$candidateAny = [];
}
if($meLevel >= 5 && !isOfficerSet($nation['chief_set'], $meLevel)) {
echo "
<select id='genlist_kick' size=1 style=color:white;background-color:black;>";
foreach($candidateAny as $general) {
if($general['no'] === $me['no']){
continue;
}
echo "
<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']} <small>({$general['leadership']}/{$general['strength']}/{$general['intel']}, {$general['killturn']})</small></option>";
}
echo "
</select>
<input type=$btn id='btn_kick' value=추방>";
}
$officerLevelText = getOfficerLevelText(11, $nation['level']);
echo "
</td>
</tr>
</table>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td colspan=4 height=5></td></tr>
<tr><td colspan=4 align=center bgcolor=blue> </td></tr>
<tr>
<td width=98 align=right id=bg1>".getOfficerLevelText(12, $nation['level'])."</td>
<td width=398>{$level[12]['name']} ".CityConst::byID($level[12]['city'])->name."</td>
<td width=98 align=right id=bg1>{$officerLevelText}</td>
<td width=398>
";
if($meLevel >= 5 && !isOfficerSet($nation['chief_set'], 11)) {
echo "
<select id='genlist_11' size=1 maxlength=15 style=color:white;background-color:black;>
<option value=0 data-officer_level='0' data-name=''>____공석____</option>";
foreach($candidateAny as $general) {
if($general['officer_level'] == 11) {
echo "<option style=color:red; selected data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} elseif($general['officer_level'] > 1) {
echo "<option style=color:orange; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} else {
echo "<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
}
}
echo "
</select>
<input class='btn_appoint' type=$btn data-officer_level='11' data-officer_level_text='{$officerLevelText}' value=임명>";
} else {
if(key_exists(11, $level)){
echo "{$level[11]['name']}".CityConst::byID($level[11]['city'])->name."";
}
}
echo "
</td>
</tr>
";
for($i=10; $i >= $lv; $i--) {
if($i % 2 == 0) { echo "<tr>"; }
$officerLevelText = getOfficerLevelText($i, $nation['level']);
echo "
<td width=98 align=right id=bg1>{$officerLevelText}</td>
<td width=398>
";
if($meLevel >= 5 && !isOfficerSet($nation['chief_set'], $i)) {
echo "
<select id='genlist_{$i}' size=1 style=color:white;background-color:black;>
<option value=0 data-officer_level='0' data-name=''>____공석____</option>";
foreach(($i%2==0?$candidateStrength:$candidateIntel) as $general) {
if($general['officer_level'] == $i) {
echo "<option style=color:red; selected data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} elseif($general['officer_level'] > 1) {
echo "<option style=color:orange; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} else {
echo "<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
}
}
echo "
</select>
<input class='btn_appoint' type=$btn data-officer_level='{$i}' data-officer_level_text='$officerLevelText' value=임명>";
} else {
$general = $level[$i]??null;
if($general){
echo "{$general['name']}".CityConst::byID($general['city'])->name."";
}
}
echo "</td>";
if($i % 2 == 1) { echo "</tr>"; }
}
echo "
<tr><td colspan=4> <font color=red>빨간색</font> 현재 임명중인 장수, <font color=orange>노란색</font> 다른 관직에 임명된 장수, 하얀색은 일반 장수를 뜻합니다.</td></tr>
</table>
";
if($meLevel == 12):
?>
<table align='center' width='1000' class='tb_layout bg0'>
<tr><td colspan='4' height='5'></td></tr>
<tr><td colspan='4' align='center' bgcolor='purple'> </td></tr>
<tr>
<td width=98 align=right id=bg1>외교권자</td>
<td width=398>
<select id="selectAmbassador" multiple="multiple">
</select>
<button id='changeAmbassador' type='button'>임명</button>
</td>
<td width=98 align=right id=bg1>조언자</td>
<td width=398>
<select id="selectAuditor" multiple="multiple">
</select>
<button id='changeAuditor' type='button'>임명</button>
</td>
</tr>
</table>
<?php
endif;
?>
<table align=center width=1000 id='officer_list' class='tb_layout bg0'>
<tr><td colspan=5 height=5></td></tr>
<?php
if($meLevel >= 5) {
$officerLevelText = getOfficerLevelText(4, $nation['level']);
echo "
<tr><td colspan=5 align=center bgcolor=orange> </td></tr>
<tr>
<td colspan=3 align=right id=bg2>{$officerLevelText} 임명</td>
<td colspan=2>
<select id='citylist_4' size=1 style=color:white;background-color:black;>
";
$cityList = $db->query('SELECT city,name,region,officer_set FROM city WHERE nation=%i ORDER BY region,level DESC,binary(name)', $nationID);
$region = 0;
foreach($cityList as $city){
if(isOfficerSet($city['officer_set'], 4)){
continue;
}
if($region != $city['region']) {
if($region != 0) {
echo "</optgroup>";
}
echo "<optgroup label=' 【 ".CityConst::$regionMap[$city['region']]." 】 ' style=color:skyblue;>";
$region = $city['region'];
}
echo "<option value='{$city['city']}' style=color:white;><span class='name_field'>{$city['name']}</span></option>";
}
echo "</optgroup>";
echo "
</select>
<select id='genlist_4' size=1 style=color:white;background-color:black;>
<option value=0 data-officer_level='0' data-name=''>____공석____</option>
";
foreach($candidateStrength as $general) {
if($general['officer_level'] == 4) {
echo "<option style=color:red; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} elseif($general['officer_level'] > 1) {
echo "<option style=color:orange; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} else {
echo "<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
}
}
echo "
</select>
<input class='btn_appoint' type=$btn data-officer_level='4' data-officer_level_text='{$officerLevelText}' value=임명>
</td>
</tr>";
$officerLevelText = getOfficerLevelText(3, $nation['level']);
echo "<tr>
<td colspan=3 align=right id=bg2>{$officerLevelText} 임명</td>
<td colspan=2>
<select id='citylist_3' size=1 style=color:white;background-color:black;>
";
$region = 0;
foreach($cityList as $city){
if(isOfficerSet($city['officer_set'], 3)){
continue;
}
if($region != $city['region']) {
if($region != 0) {
echo "</optgroup>";
}
echo "<optgroup label=' 【 ".CityConst::$regionMap[$city['region']]." 】 ' style=color:skyblue;>";
$region = $city['region'];
}
echo "<option value='{$city['city']}' style=color:white;><span class='name_field'>{$city['name']}</span></option>";
}
echo "</optgroup>";
echo "
</select>
<select id='genlist_3' size=1 style=color:white;background-color:black;>
<option value=0 data-officer_level='0' data-name=''>____공석____</option>
";
foreach($candidateIntel as $general) {
if($general['officer_level'] == 3) {
echo "<option style=color:red; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} elseif($general['officer_level'] > 1) {
echo "<option style=color:orange; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} else {
echo "<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
}
}
echo "
</select>
<input class='btn_appoint' type=$btn data-officer_level='3' data-officer_level_text='{$officerLevelText}' value=임명>
</td>
</tr>";
$officerLevelText = getOfficerLevelText(2, $nation['level']);
echo "<tr>
<td colspan=3 align=right id=bg2>{$officerLevelText} 임명</td>
<td colspan=2>
<select id='citylist_2' size=1 style=color:white;background-color:black;>
";
$region = 0;
foreach($cityList as $city){
if(isOfficerSet($city['officer_set'], 2)){
continue;
}
if($region != $city['region']) {
if($region != 0) {
echo "</optgroup>";
}
echo "<optgroup label=' 【 ".CityConst::$regionMap[$city['region']]." 】 ' style=color:skyblue;>";
$region = $city['region'];
}
echo "<option value='{$city['city']}' style=color:white;><span class='name_field'>{$city['name']}</span></option>";
}
echo "</optgroup>";
echo "
</select>
<select id='genlist_2' size=1 style=color:white;background-color:black;>
<option value=0>____<span class='name_field'>공석</span>____</option>
";
foreach ($candidateAny as $general) {
if($general['officer_level'] == 2) {
echo "<option style=color:red; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} elseif($general['officer_level'] > 1) {
echo "<option style=color:orange; data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
} else {
echo "<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']}".CityConst::byID($general['city'])->name."】</option>";
}
}
echo "
</select>
<input class='btn_appoint' type=$btn data-officer_level='2' data-officer_level_text='{$officerLevelText}' value=임명>
</td>
</tr>
<tr><td colspan=5> <font color=red>빨간색</font> 현재 임명중인 장수, <font color=orange>노란색</font> 다른 관직에 임명된 장수, 하얀색은 일반 장수를 뜻합니다.</td></tr>
";
}
echo "
<tr>
<td width=158 align=center id=bg1 colspan=2><font size=4> </font></td>
<td width=278 align=center id=bg1><font size=4> (사관) 【현재도시】</font></td>
<td width=278 align=center id=bg1><font size=4> (사관) 【현재도시】</font></td>
<td width=278 align=center id=bg1><font size=4> (사관) 【현재도시】</font></td>
</tr>
";
$citylevel = getCityLevelList();
$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){
$officerCityID = $officer['officer_city'];
if(!key_exists($officerCityID, $officerList)){
$officerList[$officerCityID] = [];
}
$officerList[$officerCityID][$officer['officer_level']] = $officer;
}
$region = 0;
$dummyOfficer = [
'name'=>'-',
'belong'=>0,
];
$textColor = newColor($nation['color']);
$nationColor = $nation['color'];
foreach($db->query('SELECT city,name,level,region,officer_set from city where nation=%i order by region,level desc,binary(name)', $nationID) as $city) {
$cityID = $city['city'];
$cityOfficerList = $officerList[$cityID]??[];
?>
<?php if($region != $city['region']): ?>
<tr><td colspan=5 height=3 id=bg1></td></tr>
<tr><td colspan=5 id=bg1><font size=4 color=skyblue> <?=CityConst::$regionMap[$city['region']]?> 】 </font></td></tr>
<?php endif; $region = $city['region']; ?>
<tr>
<td width=78 align=center style='color:<?=$textColor?>;background-color:<?=$nationColor?>;font-size:1.2em;'><?=$citylevel[$city['level']]?>】</td>
<td width=78 align=right style='color:<?=$textColor?>;background-color:<?=$nationColor?>;font-size:1.2em;'><?=$city['name']?>&nbsp;&nbsp;</td>
<?php foreach(Util::range(4, 1, -1) as $officerLevel): ?>
<?php if(key_exists($officerLevel, $cityOfficerList)):
$officer = $cityOfficerList[$officerLevel];
?>
<td style="color:<?=isOfficerSet($city['officer_set'], $officerLevel)?'orange':'white'?>;"><?=$officer['name']?>(<?=$officer['belong']?>년) 【<?=CityConst::byID($officer['city'])->name?>】</td>
<?php else: ?>
<td>-</td>
<?php endif; ?>
<?php endforeach; ?>
</tr>
<?php
}
?>
<tr><td colspan=5> <font color=orange>노란색</font> 변경 불가능, 하얀색은 변경 가능 관직입니다.</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>
+165 -212
View File
@@ -1,212 +1,165 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
$btn = Util::getPost('btn');
$defence_train = Util::getPost('defence_train', 'int', 2);
$tnmt = Util::getPost('tnmt', 'int', 1);
//$detachNPC = Util::getPost('detachNPC', 'bool');
$detachNPC = false;
$showDieImmediatelyBtn = false;
$availableDieImmediately = false;
if ($defence_train <= 60) {
$defence_train = 60;
}
else if($defence_train <= 80){
$defence_train = 80;
}
else{
$defence_train = 999;
}
if($tnmt < 0 || $tnmt > 1){
$tnmt = 1;
}
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$generalID = $session->generalID;
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
increaseRefresh("내정보", 1);
$me = General::createGeneralObjFromDB($generalID);
$myset = $me->getVar('myset');
if ($myset > 0) {
$submit = 'submit';
} else {
$submit = 'hidden';
}
if (($btn == "설정저장" || $detachNPC) && $myset > 0) {
if ($myset > 1) {
$submit = 'submit';
} else {
$submit = 'hidden';
}
if($defence_train != $me->getVar('defence_train')){
if($defence_train == 999){
$me->increaseVar('myset', -1);
$me->setVar('defence_train', $defence_train);
$me->increaseVar('train', -3);
$me->increaseVar('atmos', -3);
}
else{
$me->increaseVar('myset', -1);
$me->setVar('defence_train', $defence_train);
}
$myset -= 1;
}
if($me->getVar('tnmt') != $tnmt){
$me->setVar('tnmt', $tnmt);
}
if($me->getNPCType() == 1 && $detachNPC){
$turnterm = $gameStor->turnterm;
if($turnterm < 10){
$targetKillTurn = 30 / $turnterm;
}
else{
$targetKillTurn = 60 / $turnterm;
}
$me->setVar('killturn', $targetKillTurn);
}
}
$me->applyDB($db);
if($gameStor->turntime <= $gameStor->opentime){
//서버 가오픈시 할 수 있는 행동
if($me->getNPCType() == 0){
$showDieImmediatelyBtn = true;
if(addTurn($me->getVar('lastrefresh'), $gameStor->turnterm, 2) <= TimeUtil::now()){
$availableDieImmediately = true;
}
}
}
?>
<!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('../e_lib/jquery-3.3.1.min.js')?>
<?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('js/common.js')?>
<?=WebUtil::printJS('js/myPage.js')?>
<?=WebUtil::printCSS('../e_lib/bootstrap.min.css')?>
<?=WebUtil::printCSS('../d_shared/common.css')?>
<?=WebUtil::printCSS('css/common.css')?>
<script>
var availableDieImmediately = <?=$availableDieImmediately?'true':'false'?>;
jQuery(function($){
$('#die_immediately').click(function(){
if(!availableDieImmediately){
alert('삭제를 위해서는 생성 후 2턴 가량의 시간이 필요합니다.');
location.reload();
return false;
}
return confirm('정말로 삭제하시겠습니까?');
});
});
</script>
</head>
<body>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td> <br><?=backButton()?></td></tr>
</table>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td width=50%>
<?php generalInfo($me); ?>
<?php generalInfo2($me); ?>
</td>
<td width=50% valign=top style="padding-left:4ch;">
<form name=form1 action=b_myPage.php method=post>
토너먼트
<input type=radio name=tnmt value=0 <?=$me->getVar('tnmt')==0?"checked":""; ?>>수동참여
<input type=radio name=tnmt value=1 <?=$me->getVar('tnmt')==1?"checked":""; ?>>자동참여
<br>
<font color=orange>개막직전 남는자리가 있을경우 랜덤하게 참여합니다.</font><br><br>
수비
<input type=radio name=defence_train value=80 <?=$me->getVar('defence_train')==80?"checked":""; ?>>◎(훈사80)
<input type=radio name=defence_train value=60 <?=$me->getVar('defence_train')==60?"checked":""; ?>>○(훈사60)
<input type=radio name=defence_train value=999 <?=$me->getVar('defence_train')==999?"checked":""; ?>>×
<br><br>
<input type=<?=$submit?> name=btn style=background-color:<?=GameConst::$basecolor2?>;color:white;width:160px;height:30px;font-size:13px; value=설정저장><br>
<font color=orange>설정저장은 이달중 <?=$myset?>회 남았습니다.</font><br><br>
</form>
<?php if(!($gameStor->autorun_user['limit_minutes']??false)): ?>
<br>
<a href="c_vacation.php"><button type="button" style=background-color:<?=GameConst::$basecolor2?>;color:white;width:160px;height:30px;font-size:13px;>휴가 신청</button></a><br><br>
<?php endif; ?>
<!--빙의 해제용 삭턴 조절<br>
<a href="b_myPage.php?detachNPC=1"><button type="button" style=background-color:<?=GameConst::$basecolor2?>;color:white;width:160px;height:30px;font-size:13px;>빙의 해체 요청</button></a>-->
<?php if($showDieImmediatelyBtn): ?>
가오픈 기간 장수 삭제<br>
<a href="c_die_immediately.php" id='die_immediately'><button type="button" style=background-color:<?=GameConst::$basecolor2?>;color:white;width:160px;height:30px;font-size:13px;>장수 삭제</button></a><br><br>
<?php endif; ?>
개인용 CSS<br>
<textarea id='custom_css' style='color:white;background-color:black;width:420px;height:150px;'></textarea>
</td>
</tr>
<tr>
<td align=center id=bg1><font color=skyblue size=3>개인 기록</font></td>
<td align=center id=bg1><font color=orange size=3>전투 기록</font></td>
</tr>
<tr>
<td valign=top>
<div id='generalActionPlate'>
<?=formatHistoryToHTML(getGeneralActionLogRecent($generalID, 24), 'generalAction')?>
</div>
<button type="button" class="load_old_log btn btn-secondary btn-block" data-log_type="generalAction">이전 로그 불러오기</button>
</td>
<td valign=top>
<div id='battleDetailPlate'>
<?=formatHistoryToHTML(getBattleDetailLogRecent($generalID, 24), 'battleDetail')?>
</div>
<button type="button" class="load_old_log btn btn-secondary btn-block" data-log_type="battleDetail">이전 로그 불러오기</button>
</td>
</tr>
<tr>
<td align=center id=bg1><font color=skyblue size=3>장수 열전</font></td>
<td align=center id=bg1><font color=orange size=3>전투 결과</font></td>
</tr>
<tr>
<td valign=top>
<?=formatHistoryToHTML(getGeneralHistoryLogAll($generalID))?>
</td>
<td valign=top>
<div id='battleResultPlate'>
<?=formatHistoryToHTML(getBattleResultRecent($generalID, 24), 'battleResult')?>
</div>
<button type="button" class="load_old_log btn btn-secondary btn-block" data-log_type="battleResult">이전 로그 불러오기</button>
</td>
</tr>
</table>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td><?=backButton()?></td></tr>
<tr><td><?=banner()?></td></tr>
</table>
</body>
</html>
<?php
namespace sammo;
include "lib.php";
include "func.php";
$showDieImmediatelyBtn = false;
$availableDieImmediately = false;
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$generalID = $session->generalID;
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheValues(['turntime', 'opentime', 'autorun_user', 'npcmode']);
increaseRefresh("내정보", 1);
$me = General::createGeneralObjFromDB($generalID);
$myset = $me->getVar('myset');
if ($myset > 0) {
$submit = 'button';
} else {
$submit = 'hidden';
}
$targetTime = addTurn($me->getVar('lastrefresh'), $gameStor->turnterm, 2);
if($gameStor->turntime <= $gameStor->opentime){
//서버 가오픈시 할 수 있는 행동
if($me->getNPCType() == 0){
$showDieImmediatelyBtn = true;
if($targetTime <= TimeUtil::now()){
$availableDieImmediately = true;
}
}
}
$use_treatment = $me->getAuxVar('use_treatment')??10;
$use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn')??1;
?>
<!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>
<script>
var availableDieImmediately = <?=$availableDieImmediately?'true':'false'?>;
</script>
<?=WebUtil::printJS('../e_lib/jquery-3.3.1.min.js')?>
<?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('js/common.js')?>
<?=WebUtil::printJS('js/myPage.js')?>
<?=WebUtil::printCSS('../e_lib/bootstrap.min.css')?>
<?=WebUtil::printCSS('../d_shared/common.css')?>
<?=WebUtil::printCSS('css/common.css')?>
</head>
<body>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td> <br><?=backButton()?></td></tr>
</table>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td width=50%>
<?php generalInfo($me); ?>
<?php generalInfo2($me); ?>
</td>
<td width=50% valign=top style="padding-left:4ch;">
토너먼트
<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":""; ?>>자동참여
<br>
<span style='color:orange'>개막직전 남는자리가 있을경우 랜덤하게 참여합니다.</span><br><br>
환약 사용 <select id='use_treatment' name='use_treatment'>
<option value=10 <?=($use_treatment==10)?"selected":""; ?>>경상</option>
<option value=21 <?=($use_treatment==21)?"selected":""; ?>>중상</option>
<option value=41 <?=($use_treatment==41)?"selected":""; ?>>심각</option>
<option value=61 <?=($use_treatment==61)?"selected":""; ?>>위독</option>
<option value=100 <?=($use_treatment==100)?"selected":""; ?>>사용안함</option>
</select><br>
<span style='color:orange'>부상을 입었을 환약을 사용하는 기준입니다.</span><br><br>
<?php if(($gameStor->autorun_user['options']['chief'])??false) : ?>
자동 사령턴 허용 <select id='use_auto_nation_turn' name='use_auto_nation_turn'>
<option value=1 <?=$use_auto_nation_turn?"selected":""; ?>>허용</option>
<option value=0 <?=(!$use_auto_nation_turn)?"selected":""; ?>>허용 안함</option>
</select><br>
<span style='color:orange'>수뇌가 되었을 휴식 턴이어도 적당한 턴을 알아서 넣는 것을 허용합니다.</span><br><br>
<?php endif; ?>
수비 <select id='defence_train' name='defence_train'>
<?php foreach([90, 80, 60, 40] as $targetDefenceTrain): ?>
<option value='<?=$targetDefenceTrain?>' <?=$me->getVar('defence_train')==$targetDefenceTrain?"selected":""; ?>><?=formatDefenceTrain($targetDefenceTrain)?>(훈사<?=$targetDefenceTrain?>)</option>
<?php endforeach; ?>
<option value=999 <?=$me->getVar('defence_train')==999?"selected":""; ?>><?=formatDefenceTrain(999)?>[훈련, 사기 -3]</option>
</select>
<br><br>
<input type=<?=$submit?> id='set_my_setting' name=btn style=background-color:<?=GameConst::$basecolor2?>;color:white;width:160px;height:30px;font-size:13px; value=설정저장><br>
<span style='color:orange'>설정저장은 이달중 <?=$myset?>회 남았습니다.</span><br><br>
<?php if(!($gameStor->autorun_user['limit_minutes']??false)): ?>
<br>
<button type="button" id='vacation' style=background-color:<?=GameConst::$basecolor2?>;color:white;width:160px;height:30px;font-size:13px;>휴가 신청</button><br><br>
<?php endif; ?>
<!--빙의 해제용 삭턴 조절<br>
<a href="b_myPage.php?detachNPC=1"><button type="button" style=background-color:<?=GameConst::$basecolor2?>;color:white;width:160px;height:30px;font-size:13px;>빙의 해체 요청</button></a>-->
<?php if($showDieImmediatelyBtn): ?>
가오픈 기간 장수 삭제 (<?=substr($targetTime, 0, 19)?> 부터)<br>
<a href="c_die_immediately.php" id='die_immediately'><button type="button" style=background-color:<?=GameConst::$basecolor2?>;color:white;width:160px;height:30px;font-size:13px;>장수 삭제</button></a><br><br>
<?php endif; ?>
<?php if($gameStor->npcmode==2 && $me->getNPCType()==0): ?>
다른 장수 선택 (<?=substr($me->getAuxVar('next_change')??TimeUtil::now(), 0, 19)?> 부터)<br>
<a href="select_general_from_pool.php" id='select_general_from_pool'><button type="button" style=background-color:<?=GameConst::$basecolor2?>;color:white;width:160px;height:30px;font-size:13px;>다른 장수 선택</button></a><br><br>
<?php endif; ?>
개인용 CSS<br>
<textarea id='custom_css' style='color:white;background-color:black;width:420px;height:150px;'></textarea>
</td>
</tr>
<tr>
<td align=center id=bg1><font color=skyblue size=3>개인 기록</font></td>
<td align=center id=bg1><font color=orange size=3>전투 기록</font></td>
</tr>
<tr>
<td valign=top>
<div id='generalActionPlate'>
<?=formatHistoryToHTML(getGeneralActionLogRecent($generalID, 24), 'generalAction')?>
</div>
<button type="button" class="load_old_log btn btn-secondary btn-block" data-log_type="generalAction">이전 로그 불러오기</button>
</td>
<td valign=top>
<div id='battleDetailPlate'>
<?=formatHistoryToHTML(getBattleDetailLogRecent($generalID, 24), 'battleDetail')?>
</div>
<button type="button" class="load_old_log btn btn-secondary btn-block" data-log_type="battleDetail">이전 로그 불러오기</button>
</td>
</tr>
<tr>
<td align=center id=bg1><font color=skyblue size=3>장수 열전</font></td>
<td align=center id=bg1><font color=orange size=3>전투 결과</font></td>
</tr>
<tr>
<td valign=top>
<?=formatHistoryToHTML(getGeneralHistoryLogAll($generalID))?>
</td>
<td valign=top>
<div id='battleResultPlate'>
<?=formatHistoryToHTML(getBattleResultRecent($generalID, 24), 'battleResult')?>
</div>
<button type="button" class="load_old_log btn btn-secondary btn-block" data-log_type="battleResult">이전 로그 불러오기</button>
</td>
</tr>
</table>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td><?=backButton()?></td></tr>
<tr><td><?=banner()?></td></tr>
</table>
</body>
</html>
+7 -5
View File
@@ -64,6 +64,7 @@ if ($currentNationPolicy['reqHumanWarUrgentGold'] ?? 0) {
$autoPolicyVariable['reqHumanWarUrgentGold'] = $currentNationPolicy['reqHumanWarUrgentGold'];
}
$autoPolicy = new AutorunNationPolicy($general, ($gameStor->autorun_user)['options'], ['values' => $autoPolicyVariable], null, $nation, $gameStor->getAll(true));
$zeroPolicy = new AutorunNationPolicy($general, ($gameStor->autorun_user)['options'], null, null, $nation, $gameStor->getAll(true));
?>
@@ -90,6 +91,7 @@ $autoPolicy = new AutorunNationPolicy($general, ($gameStor->autorun_user)['optio
var availableGeneralActionPriorityItems = <?= Json::encode(AutorunGeneralPolicy::$default_priority) ?>;
var btnHelpMessage = {
'불가침제의': '군주가 NPC이고, 타국에서 원조를 받았을 때,<br>세입(금/쌀) 대비 원조량에 따라 불가침제의를 합니다.',
'선전포고': '군주가 NPC이고, 전쟁중이 아닐 때,<br>주변국중 하나를 골라 선포합니다.<br><br>선포 시점은 다음을 참고합니다.<br>- 인구율<br>- 도시내정률<br>- NPC전투장권장 금 충족률<br>- NPC전투장권장 쌀 충족률<br><br>국력이 낮은 국가를 조금 더 선호합니다.',
'천도': '인구가 많은 곳을 찾아 천도를 시도합니다.<br>영토의 가운데를 선호합니다.<br><br>도시 인구가 충분하다면, 굳이 천도하지는 않습니다.',
'유저장긴급포상': '금/쌀이 부족한 유저전투장에게 긴급하게 포상합니다.<br>국고가 권장량보다 적어지더라도 시도합니다.',
@@ -117,7 +119,7 @@ $autoPolicy = new AutorunNationPolicy($general, ($gameStor->autorun_user)['optio
'긴급내정': '전쟁중에 민심이 70 미만이거나,<br>인구가 제자리 징병이 가능하지 않을 정도로 적을 경우,<br>일정확률로 주민선정과 정착장려를 수행합니다.<br><br>통솔이 높을 수록 수행할 확률이 높습니다.',
'전투준비': '충분한 병력을 가지고 있지만 훈련과 사기가 부족한 경우 훈련과 사기진작을 수행합니다.',
'전방워프': '전투장이 충분한 병력을 가지고 있다면 전방으로 이동합니다.',
'NPC헌납': '국고가 부족한데 NPC장수가 충분한 금쌀을 가지고 있다면 일부를 헌납합니다. <br>NPC내정장은 국고가 넉넉하더라도 충분한 금쌀을 가지고 있다면 일부를 헌납합니다.',
'NPC헌납': '국고가 부족한데 NPC전쟁장이 충분한 금쌀(권장량 대비 1.5배)을 가지고 있다면 일부를 헌납합니다. <br>NPC내정장은 국고가 넉넉하더라도 충분한 금쌀을 가지고 있다면 권장량만 유지하고 헌납합니다.',
'징병': '전쟁 중 병력을 소진하였다면 재 징병합니다.<br><br>기존에 사용한 병종군 중에서 사용가능한 병종을 랜덤하게 선택합니다.<br>고급 병종을 선택할 확률이 조금 더 높습니다.<br><br>NPC의 경우 도시의 인구가 충분하지 않다면 징병을 할 확률이 감소합니다.<br><br>유저장은 최대한 고급병종을 유지하며,<br>유저장 모병이 허용되는 경우 모병을 3회할 수 있다면 모병합니다.',
'후방워프': '전쟁 중 병력을 소진하였는데 도시의 인구가 충분하지 않다면,<br>인구가 많은 도시로 이동합니다.',
'전쟁내정': '전쟁 중 수행하는 내정입니다.<br>정착장려, 기술연구의 확률이 좀 더 높고,<br>치안강화, 농지개간, 상업투자의 확률이 낮습니다.<br><br>내정이 가능하다 하더라도 전시임을 고려해,<br>30% 확률로 다른 턴을 수행합니다.',
@@ -184,7 +186,7 @@ $autoPolicy = new AutorunNationPolicy($general, ($gameStor->autorun_user)['optio
</div>
<div style='text-align:right;'><small class="form-text text-muted">
유저장긴급포상시 이보다 금이 적은 장수에게 포상합니다.<br>
0이면 보병 6 징병(<?= number_format(GameConst::$defaultStatMax * 100) ?> * 6) 가능한 금을 기준으로 하며, 그 수치는 현재 <?= number_format($autoPolicy->reqHumanWarUrgentGold) ?>입니다.</small></div>
0이면 보병 6 징병(<?= number_format(GameConst::$defaultStatMax * 100) ?> * 6) 가능한 금을 기준으로 하며, 그 수치는 현재 <?= number_format($zeroPolicy->reqHumanWarUrgentGold) ?>입니다.</small></div>
</div>
<div class="col-sm-6">
<div class="row">
@@ -193,7 +195,7 @@ $autoPolicy = new AutorunNationPolicy($general, ($gameStor->autorun_user)['optio
<input type="number" class="form-control" data-type="integer" id="reqHumanWarUrgentRice" min="0" value="0">
</div>
</div>
<div style='text-align:right;'><small class="form-text text-muted">유저장긴급포상시 이보다 쌀이 적은 장수에게 포상합니다.<br>0이면 기본 병종으로 <?= number_format(GameConst::$defaultStatMax * 100 * 6) ?>명 사살 가능한 쌀을 기준으로 하며, 그 수치는 현재 <?= number_format($autoPolicy->reqHumanWarUrgentRice) ?>입니다.</small></div>
<div style='text-align:right;'><small class="form-text text-muted">유저장긴급포상시 이보다 쌀이 적은 장수에게 포상합니다.<br>0이면 기본 병종으로 <?= number_format(GameConst::$defaultStatMax * 100 * 6) ?>명 사살 가능한 쌀을 기준으로 하며, 그 수치는 현재 <?= number_format($zeroPolicy->reqHumanWarUrgentRice) ?>입니다.</small></div>
</div>
</div>
<div class="form-group row">
@@ -205,7 +207,7 @@ $autoPolicy = new AutorunNationPolicy($general, ($gameStor->autorun_user)['optio
</div>
</div>
<div style='text-align:right;'><small class="form-text text-muted">유저전투장에게 주는 금입니다. 이보다 적으면 포상합니다. <br>
0이면 유저전투장 긴급포상 금의 3배를 기준으로 하며, 수치는 현재 <?= number_format($autoPolicy->reqHumanWarRecommandGold) ?>입니다.</small></div>
0이면 유저전투장 긴급포상 금의 2배를 기준으로 하며, 수치는 현재 <?= number_format($autoPolicy->reqHumanWarRecommandGold) ?>입니다.</small></div>
</div>
<div class="col-sm-6">
<div class="row">
@@ -215,7 +217,7 @@ $autoPolicy = new AutorunNationPolicy($general, ($gameStor->autorun_user)['optio
</div>
</div>
<div style='text-align:right;'><small class="form-text text-muted">유저전투장에게 주는 쌀입니다. 이보다 적으면 포상합니다. <br>
0이면 유저전투장 긴급포상 쌀의 3배를 기준으로 하며, 수치는 현재 <?= number_format($autoPolicy->reqHumanWarRecommandRice) ?>입니다.</small></div>
0이면 유저전투장 긴급포상 쌀의 2배를 기준으로 하며, 수치는 현재 <?= number_format($autoPolicy->reqHumanWarRecommandRice) ?>입니다.</small></div>
</div>
</div>
<div class="form-group row">
+131 -127
View File
@@ -1,127 +1,131 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
//로그인 검사
$commandType = Util::getReq('command', 'string');
$turnList = array_map('intval', explode('_', Util::getReq('turnList', 'string', '0')));
$isChiefTurn = Util::getReq('is_chief', 'bool', false);
function die_redirect()
{
global $isChiefTurn;
if(!$isChiefTurn){
header('location:index.php', true, 303);
}
else{
header('location:b_chiefcenter.php', true, 303);
}
die();
}
if(!$turnList || !$commandType){
die_redirect();
}
if(!is_array($turnList)){
die_redirect();
}
$session = Session::requireGameLogin()->setReadOnly();
$db = DB::db();
if(!$isChiefTurn && !in_array($commandType, Util::array_flatten(GameConst::$availableGeneralCommand))){
die_redirect();
}
if($isChiefTurn && !in_array($commandType, Util::array_flatten(GameConst::$availableChiefCommand))){
die_redirect();
}
$gameStor = KVStorage::getStorage($db, 'game_env')->turnOnCache();
$env = $gameStor->getAll();
$general = General::createGeneralObjFromDB($session->generalID);
if(!$isChiefTurn){
$commandObj = buildGeneralCommandClass($commandType, $general, $env);
}
else{
if($general->getVar('officer_level') < 5){
die_redirect();
}
$commandObj = buildNationCommandClass($commandType, $general, $env, new LastTurn());
}
if($commandObj->isArgValid()){
//인자가 필요없는 타입의 경우 processing에서 '전혀' 처리하지 않음!
die_redirect();
}
if(!$commandObj->hasPermissionToReserve()){
die_redirect();
}
$jsList = $commandObj->getJSFiles();
$cssList = $commandObj->getCSSFiles();
?>
<!DOCTYPE html>
<html>
<head>
<title><?=$commandObj->getName()?></title>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<?=WebUtil::printJS('../e_lib/jquery-3.3.1.min.js')?>
<?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('../d_shared/common_path.js')?>
<?=WebUtil::printJS('js/common.js')?>
<?=WebUtil::printJS('d_shared/base_map.js')?>
<?=WebUtil::printJS('js/map.js')?>
<?=WebUtil::printJS('js/processing.js')?>
<script>
window.serverNick = '<?=DB::prefix()?>';
window.serverID = '<?=UniqueConst::$serverID?>';
window.command = '<?=$commandType?>';
window.turnList = [<?=join(', ',$turnList)?>];
window.isChiefTurn = <?=$isChiefTurn?'true':'false'?>;
</script>
<?php
foreach($jsList as $js){
print(WebUtil::printJS($js));
}
?>
<?=WebUtil::printCSS('../e_lib/bootstrap.min.css')?>
<?=WebUtil::printCSS('../d_shared/common.css')?>
<?=WebUtil::printCSS('css/common.css')?>
<?=WebUtil::printCSS('css/main.css')?>
<?=WebUtil::printCSS('css/map.css')?>
<?php
foreach($cssList as $css){
print(WebUtil::printCSS($css));
}
?>
</head>
<body class="img_back">
<table class="tb_layout bg0" style="width:1000px;margin:auto;">
<tr><td class="bg1" style='text-align:center;'><?=$commandObj->getName()?></td></tr>
<tr><td>
<input type=button value='돌아가기' onclick="history.back();"><br>
</td></tr></table>
<div class="tb_layout bg0" style="width:1000px;margin:auto;padding-bottom:2em;border:solid 1px gray;">
<?=$commandObj->getForm()?>
</div>
<table class="tb_layout bg0" style="width:1000px;margin:auto;">
<tr><td>
<input type=button value='돌아가기' onclick="history.back();"><br>
<?=banner()?>
</td></tr></table>
</body>
</html>
<?php
namespace sammo;
include "lib.php";
include "func.php";
//로그인 검사
$commandType = Util::getReq('command', 'string');
$turnList = array_map('intval', explode('_', Util::getReq('turnList', 'string', '0')));
$isChiefTurn = Util::getReq('is_chief', 'bool', false);
function die_redirect()
{
global $isChiefTurn;
if(!$isChiefTurn){
header('location:index.php', true, 303);
}
else{
header('location:b_chiefcenter.php', true, 303);
}
die();
}
if(!$turnList || !$commandType){
die_redirect();
}
if(!is_array($turnList)){
die_redirect();
}
$session = Session::requireGameLogin()->setReadOnly();
$db = DB::db();
if(!$isChiefTurn && !in_array($commandType, Util::array_flatten(GameConst::$availableGeneralCommand))){
die_redirect();
}
if($isChiefTurn && !in_array($commandType, Util::array_flatten(GameConst::$availableChiefCommand))){
die_redirect();
}
$gameStor = KVStorage::getStorage($db, 'game_env')->turnOnCache();
$env = $gameStor->getAll();
$general = General::createGeneralObjFromDB($session->generalID);
if(!$isChiefTurn){
$commandObj = buildGeneralCommandClass($commandType, $general, $env);
}
else{
if($general->getVar('officer_level') < 5){
die_redirect();
}
$commandObj = buildNationCommandClass($commandType, $general, $env, new LastTurn());
}
if($commandObj->isArgValid()){
//인자가 필요없는 타입의 경우 processing에서 '전혀' 처리하지 않음!
die_redirect();
}
if(!$commandObj->hasPermissionToReserve()){
die_redirect();
}
$jsList = $commandObj->getJSFiles();
$cssList = $commandObj->getCSSFiles();
?>
<!DOCTYPE html>
<html>
<head>
<title><?=$commandObj->getName()?></title>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<?=WebUtil::printJS('../e_lib/jquery-3.3.1.min.js')?>
<?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('../e_lib/select2/select2.full.min.js')?>
<?=WebUtil::printJS('../d_shared/common_path.js')?>
<?=WebUtil::printJS('js/common.js')?>
<?=WebUtil::printJS('d_shared/base_map.js')?>
<?=WebUtil::printJS('js/map.js')?>
<?=WebUtil::printJS('js/processing.js')?>
<script>
window.serverNick = '<?=DB::prefix()?>';
window.serverID = '<?=UniqueConst::$serverID?>';
window.command = '<?=$commandType?>';
window.turnList = [<?=join(', ',$turnList)?>];
window.isChiefTurn = <?=$isChiefTurn?'true':'false'?>;
</script>
<?php
foreach($jsList as $js){
print(WebUtil::printJS($js));
}
?>
<?=WebUtil::printCSS('../e_lib/bootstrap.min.css')?>
<?=WebUtil::printCSS('../e_lib/select2/select2.min.css')?>
<?=WebUtil::printCSS('../e_lib/select2/select2-bootstrap4.css')?>
<?=WebUtil::printCSS('../d_shared/common.css')?>
<?=WebUtil::printCSS('css/common.css')?>
<?=WebUtil::printCSS('css/main.css')?>
<?=WebUtil::printCSS('css/map.css')?>
<?=WebUtil::printCSS('css/processing.css')?>
<?php
foreach($cssList as $css){
print(WebUtil::printCSS($css));
}
?>
</head>
<body class="img_back">
<table class="tb_layout bg0" style="width:1000px;margin:auto;">
<tr><td class="bg1" style='text-align:center;'><?=$commandObj->getName()?></td></tr>
<tr><td>
<input type=button value='돌아가기' onclick="history.back();"><br>
</td></tr></table>
<div class="tb_layout bg0" style="width:1000px;margin:auto;padding-bottom:2em;border:solid 1px gray;">
<?=$commandObj->getForm()?>
</div>
<table class="tb_layout bg0" style="width:1000px;margin:auto;">
<tr><td>
<input type=button value='돌아가기' onclick="history.back();"><br>
<?=banner()?>
</td></tr></table>
</body>
</html>
+551 -480
View File
@@ -1,481 +1,552 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
$session = Session::requireLogin()->setReadOnly();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$startYear = $gameStor->getValue('startyear');
?>
<!DOCTYPE html>
<html>
<head>
<title><?=UniqueConst::$serverName?>: 전투 시뮬레이터</title>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1100" />
<?=WebUtil::printCSS('../e_lib/bootstrap.min.css')?>
<?=WebUtil::printCSS('../d_shared/common.css')?>
<?=WebUtil::printCSS('css/common.css')?>
<?=WebUtil::printCSS('css/battle_simulator.css')?>
<?=WebUtil::printJS('../d_shared/common_path.js')?>
<?=WebUtil::printJS('../e_lib/jquery-3.3.1.min.js')?>
<?=WebUtil::printJS('../e_lib/moment.min.js')?>
<?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('../e_lib/download2.js')?>
<?=WebUtil::printJS('js/common.js')?>
<script>
var defaultSpecialDomestic = '<?=GameConst::$defaultSpecialDomestic?>';
</script>
<?=WebUtil::printJS('js/battle_simulator.js')?>
</head>
<body>
<div id="container">
<div class="card mb-3">
<div class="card-header">
전역 설정
</div>
<div class="card-body dragpad_battle">
<div class="row">
<div class="col-sm-6">
<div class="input-group">
<input type="number" class="form-control" aria-describedby="text_year" value="<?=$startYear?>" disabled>
<div class="input-group-append">
<span class="input-group-text"> 시작</span>
</div>
<input type="number" class="form-control" id="year" value="<?=$startYear+3?>" min="<?=$startYear?>">
<div class="input-group-append">
<span class="input-group-text"></span>
</div>
<input type="number" class="form-control" id="month" value="1" min="1" max="12">
<div class="input-group-append">
<span class="input-group-text"></span>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="btn-toolbar" role="toolbar">
<div class="input-group mr-2" role="group">
<div class="input-group-prepend">
<span class="input-group-text">반복 횟수</span>
</div>
<select class="custom-select" id="repeat_cnt">
<option value="1">1 (로그 표기)</option>
<option value="1000">1000 (요약 표기)</option>
</select>
</div>
<div class="btn-group mr-2" role="group">
<button type="button" class="btn btn-danger btn-begin_battle">전투</button>
</div>
<div class="btn-group mr-2" role="group">
<button type="button" class="btn btn-info btn-battle-save">모두 저장</button>
<input type="file" class="form_load_battle_file" accept=".json" style="display: none;" />
<button type="button" class="btn btn-primary btn-battle-load">모두 불러오기</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm">
<div class="card mb-2 attacker_nation">
<div class="card-header">
출병국 설정
</div>
<div class="card-body nation_detail dragpad_battle">
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">국가 성향</span>
</div>
<select class="custom-select form_nation_type" style="width:25ch;">
<?php foreach(GameConst::$availableNationType as $typeID): ?>
<?php $nationTypeClass = buildNationTypeClass($typeID) ?>
<option value="<?=$typeID?>"><?=$nationTypeClass->getName()?> (<?=$nationTypeClass::$pros?>, <?=$nationTypeClass::$cons?>)</option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">기술</span>
</div>
<input type="number" class="form-control form_tech" value="1" min="0" max="12">
<div class="input-group-append">
<span class="input-group-text">등급</span>
</div>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">국가 규모</span>
</div>
<select class="custom-select form_nation_level">
<?php foreach(getNationLevelList() as $nationLevel => [$name,$chiefCnt,$cityCnt]): ?>
<option value="<?=$nationLevel?>"><?=$name?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">도시 규모</span>
</div>
<select class="custom-select form_city_level">
<?php foreach(getCityLevelList() as $levelID => $name): ?>
<option value="<?=$levelID?>"><?=$name?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">수도</span>
</div>
<div class="input-group-append btn-group btn-group-toggle" data-toggle="buttons">
<label class="btn btn-secondary">
<input type="radio" name="is_attacker_capital" class="form_is_capital" value="1" autocomplete="off">Y
</label>
<label class="btn btn-secondary active">
<input type="radio" name="is_attacker_capital" class="form_is_capital" value="2" autocomplete="off" checked>N
</label>
</div>
</div>
<div class="input-group mb-1">
</div>
</div>
</div>
<div class="card mb-2 attacker_form general_form" data-general_no='1'>
<div class="card-header">
<div class="float-sm-left" style="line-height:25px;">출병자 설정</div>
<div class="float-sm-right btn-toolbar" role="toolbar">
<div class="btn-group btn-group-sm mr-2" role="group">
<button type="button" class="btn btn-info btn-general-save">저장</button>
<input type="file" class="form_load_general_file" accept=".json" style="display: none;" />
<button type="button" class="btn btn-primary btn-general-load">불러오기</button>
</div>
</div>
</div>
</div>
</div><!-- <div class="col-sm"> -->
<div class="col-sm defender-column">
<div class="card mb-2 defender_nation">
<div class="card-header">
수비국 설정
</div>
<div class="card-body dragpad_battle">
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">국가 성향</span>
</div>
<select class="custom-select form_nation_type" style="width:25ch;">
<?php foreach(GameConst::$availableNationType as $typeID): ?>
<?php $nationTypeObj = buildNationTypeClass($typeID) ?>
<option value="<?=$typeID?>"><?=$nationTypeObj->getName()?> (<?=$nationTypeObj::$pros?>, <?=$nationTypeObj::$cons?>)</option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">기술</span>
</div>
<input type="number" class="form-control form_tech" value="1" min="0" max="12">
<div class="input-group-append">
<span class="input-group-text">등급</span>
</div>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">국가 규모</span>
</div>
<select class="custom-select form_nation_level">
<?php foreach(getNationLevelList() as $nationLevel => [$name,$chiefCnt,$cityCnt]): ?>
<option value="<?=$nationLevel?>"><?=$name?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">도시 규모</span>
</div>
<select class="custom-select form_city_level">
<?php foreach(getCityLevelList() as $levelID => $name): ?>
<option value="<?=$levelID?>"><?=$name?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">수도</span>
</div>
<div class="input-group-append btn-group btn-group-toggle" data-toggle="buttons">
<label class="btn btn-secondary">
<input type="radio" name="is_defender_capital" class="form_is_capital" value="1" autocomplete="off">Y
</label>
<label class="btn btn-secondary active">
<input type="radio" name="is_defender_capital" class="form_is_capital" value="0" autocomplete="off" checked>N
</label>
</div>
</div>
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">수비</span>
</div>
<input type="number" class="form-control form_def" id="city_def" value="1000" min="10" step="10">
<div class="input-group-prepend">
<span class="input-group-text">성벽</span>
</div>
<input type="number" class="form-control form_wall" id="city_wall" value="1000" min="0" step="10">
</div>
</div>
</div>
<div class="card mb-2 defender_add_form">
<div class="card-header">
<div class="float-sm-left" style="line-height:25px;">수비자 설정</div>
<div class="float-sm-right btn-toolbar" role="toolbar">
<div class="btn-group btn-group-sm mr-2" role="group">
<button type="button" class="btn btn-dark btn-reorder_defender">수비 순서대로 정렬</button>
</div>
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-success add-defender">추가</button>
</div>
</div>
</div>
</div>
<div class="card mb-2 form_sample">
<div class="card-header">
<div class="float-sm-left" style="line-height:25px;">수비자 설정</div>
<div class="float-sm-right btn-toolbar" role="toolbar">
<div class="btn-group btn-group-sm mr-2" role="group">
<button type="button" class="btn btn-info btn-general-save">저장</button>
<input type="file" class="form_load_general_file" accept=".json" style="display: none;" />
<button type="button" class="btn btn-primary btn-general-load">불러오기</button>
</div>
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-warning copy-defender">복제</button>
<button type="button" class="btn btn-danger delete-defender">제거</button>
</div>
</div>
</div>
<div class="card-body general_detail">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">이름</span>
</div>
<input type="text" class="form-control form_general_name" value="무명" style="width:15ch;">
<div class="input-group-prepend">
<span class="input-group-text">직위</span>
</div>
<select class="custom-select form_officer_level" style="width:8ch;">
<option value="1">일반</option>
<option value="4">태수</option>
<option value="3">군사</option>
<option value="2">종사</option>
<option value="10">무장 수뇌</option>
<option value="9">지장 수뇌</option>
<option value="11">참모</option>
<option value="12">군주</option>
</select>
<div class="input-group-prepend">
<span class="input-group-text">Level</span>
</div>
<input type="number" class="form-control form_exp_level" value="20" min="0" max="300" step="1">
</div>
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">통솔</span>
</div>
<input type="number" class="form-control form_leadership" value="50" min="1" max="300" step="1">
<div class="input-group-prepend">
<span class="input-group-text">무력</span>
</div>
<input type="number" class="form-control form_strength" value="50" min="1" max="300" step="1">
<div class="input-group-prepend">
<span class="input-group-text">지력</span>
</div>
<input type="number" class="form-control form_intel" value="50" min="1" max="300" step="1">
</div>
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">명마</span>
</div>
<select class="custom-select form_general_horse">
<option value='None'>-</option>
<?php foreach(GameConst::$allItems['horse'] as $horseID=>$cnt): ?>
<option value="<?=$horseID?>"><?=getItemName($horseID)?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">무기</span>
</div>
<select class="custom-select form_general_weap">
<option value='None'>-</option>
<?php foreach(GameConst::$allItems['weapon'] as $weaponID=>$cnt): ?>
<option value="<?=$weaponID?>"><?=getItemName($weaponID)?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">서적</span>
</div>
<select class="custom-select form_general_book">
<option value='None'>-</option>
<?php foreach(GameConst::$allItems['book'] as $bookID=>$cnt): ?>
<option value="<?=$bookID?>"><?=getItemName($bookID)?></option>
<?php endforeach; ?>
</select>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">부상</span>
</div>
<input type="number" class="form-control form_injury" value="0" min="0" max="80" step="1">
<div class="input-group-append">
<span class="input-group-text">%(<span class="injury_helptext">건강</span>)</span>
</div>
<div class="input-group-prepend">
<span class="input-group-text">군량</span>
</div>
<input type="number" class="form-control form_rice" value="5000" min="50" max="40000" step="50">
<div class="input-group-prepend">
<span class="input-group-text">도구</span>
</div>
<select class="custom-select form_general_item">
<option value='None'>-</option>
<?php foreach(GameConst::$allItems['item'] as $itemID=>$cnt): ?>
<option value="<?=$itemID?>"><?=getItemName($itemID)?></option>
<?php endforeach; ?>
</select>
</div>
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">병종</span>
</div>
<select class="custom-select form_crewtype">
<?php foreach(GameUnitConst::all() as $crewTypeID => $crewType): ?>
<?php if($crewType->armType === GameUnitConst::T_CASTLE){ continue; } ?>
<option value="<?=$crewTypeID?>"><?=$crewType->name?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">병사</span>
</div>
<input type="number" class="form-control form_crew" value="7000" min="100" step="100">
<div class="input-group-prepend">
<span class="input-group-text">성격</span>
</div>
<select class="custom-select form_general_character">
<?php foreach(getCharacterList(false) as $characterID => [$name,$info]): ?>
<option value="<?=$characterID?>"><?=$name?></option>
<?php endforeach; ?>
</select>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">훈련</span>
</div>
<input type="number" class="form-control form_train" value="100" min="40" max="<?=GameConst::$maxTrainByWar?>" step="1">
<div class="input-group-prepend">
<span class="input-group-text">사기</span>
</div>
<input type="number" class="form-control form_atmos" value="100" min="40" max="<?=GameConst::$maxAtmosByWar?>" step="1">
<div class="input-group-prepend">
<span class="input-group-text">전특</span>
</div>
<select class="custom-select form_general_special_war">
<?php foreach(SpecialityHelper::getSpecialWarList(false) as $specialWarID =>$specialObj): ?>
<option value="<?=$specialWarID?>"><?=$specialObj->getName()?></option>
<?php endforeach; ?>
</select>
</div>
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">보병숙련</span>
</div>
<select class="custom-select form_dex1">
<?php foreach(getDexLevelList() as $dexLevel => [$dexAmount, $color, $name]): ?>
<option value="<?=$dexAmount?>"><?="{$name} (".number_format($dexAmount).")"?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">궁병숙련</span>
</div>
<select class="custom-select form_dex2">
<?php foreach(getDexLevelList() as $dexLevel => [$dexAmount, $color, $name]): ?>
<option value="<?=$dexAmount?>"><?="{$name} (".number_format($dexAmount).")"?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">기병숙련</span>
</div>
<select class="custom-select form_dex3">
<?php foreach(getDexLevelList() as $dexLevel => [$dexAmount, $color, $name]): ?>
<option value="<?=$dexAmount?>"><?="{$name} (".number_format($dexAmount).")"?></option>
<?php endforeach; ?>
</select>
</div>
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">귀병숙련</span>
</div>
<select class="custom-select form_dex4">
<?php foreach(getDexLevelList() as $dexLevel => [$dexAmount, $color, $name]): ?>
<option value="<?=$dexAmount?>"><?="{$name} (".number_format($dexAmount).")"?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">차병숙련</span>
</div>
<select class="custom-select form_dex5">
<?php foreach(getDexLevelList() as $dexLevel => [$dexAmount, $color, $name]): ?>
<option value="<?=$dexAmount?>"><?="{$name} (".number_format($dexAmount).")"?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend only_defender">
<span class="input-group-text">수비여부</span>
</div>
<select class="custom-select form_defence_train only_defender">
<option value="80">훈사 80</option>
<option value="60">훈사 60</option>
<option value="999">안함</option>
</select>
</div>
</div>
</div>
</div><!-- <div class="col-sm"> -->
</div>
<div class="card mb-3">
<div class="card-header">
전투 요약
</div>
<table class="table">
<tbody id="battle_result_summary">
<tr><th style='width:18ch;'>전투 일시</th><td id='result_datetime'></td></tr>
<tr><th>전투 횟수</th><td id='result_warcnt'></td></tr>
<tr><th>전투 페이즈</th><td id='result_phase'></td></tr>
<tr><th> 피해</th><td><span id='result_killed'>0</span><span id='result_varKilled'> (<span id='result_minKilled'>0</span> ~ <span id='result_maxKilled'>0</span>)</span></td></tr>
<tr><th>받은 피해</th><td><span id='result_dead'>0</span><span id='result_varDead'> (<span id='result_minDead'>0</span> ~ <span id='result_maxDead'>0</span>)</span></td></tr>
<tr><th>출병자 군량 소모</th><td id='result_attackerRice'></td></tr>
<tr><th>수비자 군량 소모</th><td id='result_defenderRice'></td></tr>
<tr><th>공격자 스킬</th><td id='result_attackerSkills'></td></tr>
<tr class='result_defenderSkills'><th>수비자1 스킬</th><td></td></tr>
</tbody>
</table>
</div>
<div class="row">
<div class="col-sm">
<div class="card mb-3">
<div class="card-header">
마지막 전투 로그
</div>
<div class="card-body" id="generalBattleResultLog">
</div>
</div>
</div>
<div class="col-sm">
<div class="card mb-3">
<div class="card-header">
마지막 전투 상세 로그
</div>
<div class="card-body" id="generalBattleDetailLog">
</div>
</div>
</div>
</div>
</div>
</body>
<?php
namespace sammo;
include "lib.php";
include "func.php";
$session = Session::requireLogin()->setReadOnly();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheValues(['startyear', 'year']);
$startYear = $gameStor->startyear;
$year = $gameStor->year;
$me = $db->queryFirstRow('SELECT no, nation, city FROM general WHERE owner =%i', Session::getUserID());
if($me){
$generalID = $me['no'];
$nationID = $me['nation'];
$city = $db->queryFirstRow('SELECT city, level, def, wall FROM city WHERE city = %i', $me['city']);
}
else{
$generalID = 0;
$nationID = 0;
$city = [
'city'=>0,
'level'=>5,
'def'=>1000,
'wall'=>1000,
];
}
if($nationID){
$nation = $db->queryFirstRow('SELECT level, type, tech, capital FROM nation WHERE nation = %i', $nationID);
}
else{
$nation = null;
}
?>
<!DOCTYPE html>
<html>
<head>
<title><?=UniqueConst::$serverName?>: 전투 시뮬레이터</title>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1100" />
<?=WebUtil::printCSS('../e_lib/bootstrap.min.css')?>
<?=WebUtil::printCSS('../d_shared/common.css')?>
<?=WebUtil::printCSS('css/common.css')?>
<?=WebUtil::printCSS('css/battle_simulator.css')?>
<?=WebUtil::printJS('../d_shared/common_path.js')?>
<?=WebUtil::printJS('../e_lib/jquery-3.3.1.min.js')?>
<?=WebUtil::printJS('../e_lib/moment.min.js')?>
<?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('../e_lib/download2.js')?>
<?=WebUtil::printJS('js/common.js')?>
<script>
var defaultSpecialDomestic = '<?=GameConst::$defaultSpecialDomestic?>';
var city = <?=Json::encode($city)?>;
var nation = <?=Json::encode($nation)?>;
</script>
<?=WebUtil::printJS('js/battle_simulator.js')?>
</head>
<body>
<div id="container">
<div class="card mb-3">
<div class="card-header">
전역 설정
</div>
<div class="card-body dragpad_battle">
<div class="row">
<div class="col-sm-6">
<div class="input-group">
<input type="number" class="form-control" aria-describedby="text_year" value="<?=$startYear?>" disabled>
<div class="input-group-append">
<span class="input-group-text"> 시작</span>
</div>
<input type="number" class="form-control" id="year" value="<?=$year?>" min="<?=$startYear?>">
<div class="input-group-append">
<span class="input-group-text"></span>
</div>
<input type="number" class="form-control" id="month" value="1" min="1" max="12">
<div class="input-group-append">
<span class="input-group-text"></span>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="btn-toolbar" role="toolbar">
<div class="input-group mr-2" role="group">
<div class="input-group-prepend">
<span class="input-group-text">반복 횟수</span>
</div>
<select class="custom-select" id="repeat_cnt">
<option value="1">1 (로그 표기)</option>
<option value="1000">1000 (요약 표기)</option>
</select>
</div>
<div class="btn-group mr-2" role="group">
<button type="button" class="btn btn-danger btn-begin_battle">전투</button>
</div>
<div class="btn-group mr-2" role="group">
<button type="button" class="btn btn-info btn-battle-save">모두 저장</button>
<input type="file" class="form_load_battle_file" accept=".json" style="display: none;" />
<button type="button" class="btn btn-primary btn-battle-load">모두 불러오기</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm">
<div class="card mb-2 attacker_nation">
<div class="card-header">
출병국 설정
</div>
<div class="card-body nation_detail dragpad_battle">
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">국가 성향</span>
</div>
<select class="custom-select form_nation_type" style="width:25ch;">
<?php foreach(GameConst::$availableNationType as $typeID): ?>
<?php $nationTypeClass = buildNationTypeClass($typeID) ?>
<option value="<?=$typeID?>"><?=$nationTypeClass->getName()?> (<?=$nationTypeClass::$pros?>, <?=$nationTypeClass::$cons?>)</option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">기술</span>
</div>
<input type="number" class="form-control form_tech" value="1" min="0" max="12">
<div class="input-group-append">
<span class="input-group-text">등급</span>
</div>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">국가 규모</span>
</div>
<select class="custom-select form_nation_level">
<?php foreach(getNationLevelList() as $nationLevel => [$name,$chiefCnt,$cityCnt]): ?>
<option value="<?=$nationLevel?>"><?=$name?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">도시 규모</span>
</div>
<select class="custom-select form_city_level">
<?php foreach(getCityLevelList() as $levelID => $name): ?>
<option value="<?=$levelID?>"><?=$name?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">수도</span>
</div>
<div class="input-group-append btn-group btn-group-toggle" data-toggle="buttons">
<label class="btn btn-secondary">
<input type="radio" name="is_attacker_capital" class="form_is_capital" value="1" autocomplete="off">Y
</label>
<label class="btn btn-secondary active">
<input type="radio" name="is_attacker_capital" class="form_is_capital" value="0" autocomplete="off">N
</label>
</div>
</div>
<div class="input-group mb-1">
</div>
</div>
</div>
<div class="card mb-2 attacker_form general_form" data-general_no='1'>
<div class="card-header">
<div class="float-sm-left" style="line-height:25px;">출병자 설정</div>
<div class="float-sm-right btn-toolbar" role="toolbar">
<div class="btn-group btn-group-sm mr-2" role="group">
<button type="button" class="btn btn-success btn-general-import-server">서버에서 가져오기</button>
</div>
<div class="btn-group btn-group-sm mr-2" role="group">
<button type="button" class="btn btn-info btn-general-save">저장</button>
<input type="file" class="form_load_general_file" accept=".json" style="display: none;" />
<button type="button" class="btn btn-primary btn-general-load">불러오기</button>
</div>
</div>
</div>
</div>
</div><!-- <div class="col-sm"> -->
<div class="col-sm defender-column">
<div class="card mb-2 defender_nation">
<div class="card-header">
수비국 설정
</div>
<div class="card-body dragpad_battle">
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">국가 성향</span>
</div>
<select class="custom-select form_nation_type" style="width:25ch;">
<?php foreach(GameConst::$availableNationType as $typeID): ?>
<?php $nationTypeObj = buildNationTypeClass($typeID) ?>
<option value="<?=$typeID?>"><?=$nationTypeObj->getName()?> (<?=$nationTypeObj::$pros?>, <?=$nationTypeObj::$cons?>)</option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">기술</span>
</div>
<input type="number" class="form-control form_tech" value="1" min="0" max="12">
<div class="input-group-append">
<span class="input-group-text">등급</span>
</div>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">국가 규모</span>
</div>
<select class="custom-select form_nation_level">
<?php foreach(getNationLevelList() as $nationLevel => [$name,$chiefCnt,$cityCnt]): ?>
<option value="<?=$nationLevel?>"><?=$name?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">도시 규모</span>
</div>
<select class="custom-select form_city_level">
<?php foreach(getCityLevelList() as $levelID => $name): ?>
<option value="<?=$levelID?>"><?=$name?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">수도</span>
</div>
<div class="input-group-append btn-group btn-group-toggle" data-toggle="buttons">
<label class="btn btn-secondary">
<input type="radio" name="is_defender_capital" class="form_is_capital" value="1" autocomplete="off">Y
</label>
<label class="btn btn-secondary active">
<input type="radio" name="is_defender_capital" class="form_is_capital" value="0" autocomplete="off">N
</label>
</div>
</div>
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">수비</span>
</div>
<input type="number" class="form-control form_def" id="city_def" value="1000" min="10" step="10">
<div class="input-group-prepend">
<span class="input-group-text">성벽</span>
</div>
<input type="number" class="form-control form_wall" id="city_wall" value="1000" min="0" step="10">
</div>
</div>
</div>
<div class="card mb-2 defender_add_form">
<div class="card-header">
<div class="float-sm-left" style="line-height:25px;">수비자 설정</div>
<div class="float-sm-right btn-toolbar" role="toolbar">
<div class="btn-group btn-group-sm mr-2" role="group">
<button type="button" class="btn btn-dark btn-reorder_defender">수비 순서대로 정렬</button>
</div>
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-success add-defender">추가</button>
</div>
</div>
</div>
</div>
<div class="card mb-2 form_sample">
<div class="card-header">
<div class="float-sm-left" style="line-height:25px;">수비자 설정</div>
<div class="float-sm-right btn-toolbar" role="toolbar">
<div class="btn-group btn-group-sm mr-2" role="group">
<button type="button" class="btn btn-success btn-general-import-server">서버에서 가져오기</button>
</div>
<div class="btn-group btn-group-sm mr-2" role="group">
<button type="button" class="btn btn-info btn-general-save">저장</button>
<input type="file" class="form_load_general_file" accept=".json" style="display: none;" />
<button type="button" class="btn btn-primary btn-general-load">불러오기</button>
</div>
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-warning copy-defender">복제</button>
<button type="button" class="btn btn-danger delete-defender">제거</button>
</div>
</div>
</div>
<div class="card-body general_detail">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">이름</span>
</div>
<input type="text" class="form-control form_general_name" value="무명" style="width:15ch;">
<div class="input-group-prepend">
<span class="input-group-text">직위</span>
</div>
<select class="custom-select form_officer_level" style="width:8ch;">
<option value="1">일반</option>
<option value="4">태수</option>
<option value="3">군사</option>
<option value="2">종사</option>
<option value="10">무장 수뇌</option>
<option value="9">지장 수뇌</option>
<option value="11">참모</option>
<option value="12">군주</option>
</select>
<div class="input-group-prepend">
<span class="input-group-text">Level</span>
</div>
<input type="number" class="form-control form_exp_level" value="20" min="0" max="300" step="1">
</div>
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">통솔</span>
</div>
<input type="number" class="form-control form_leadership" value="50" min="1" max="300" step="1">
<div class="input-group-prepend">
<span class="input-group-text">무력</span>
</div>
<input type="number" class="form-control form_strength" value="50" min="1" max="300" step="1">
<div class="input-group-prepend">
<span class="input-group-text">지력</span>
</div>
<input type="number" class="form-control form_intel" value="50" min="1" max="300" step="1">
</div>
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">명마</span>
</div>
<select class="custom-select form_general_horse">
<option value='None'>-</option>
<?php foreach(GameConst::$allItems['horse'] as $horseID=>$cnt): ?>
<option value="<?=$horseID?>"><?=getItemName($horseID)?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">무기</span>
</div>
<select class="custom-select form_general_weap">
<option value='None'>-</option>
<?php foreach(GameConst::$allItems['weapon'] as $weaponID=>$cnt): ?>
<option value="<?=$weaponID?>"><?=getItemName($weaponID)?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">서적</span>
</div>
<select class="custom-select form_general_book">
<option value='None'>-</option>
<?php foreach(GameConst::$allItems['book'] as $bookID=>$cnt): ?>
<option value="<?=$bookID?>"><?=getItemName($bookID)?></option>
<?php endforeach; ?>
</select>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">부상</span>
</div>
<input type="number" class="form-control form_injury" value="0" min="0" max="80" step="1">
<div class="input-group-append">
<span class="input-group-text">%(<span class="injury_helptext">건강</span>)</span>
</div>
<div class="input-group-prepend">
<span class="input-group-text">군량</span>
</div>
<input type="number" class="form-control form_rice" value="5000" min="50" max="40000" step="50">
<div class="input-group-prepend">
<span class="input-group-text">도구</span>
</div>
<select class="custom-select form_general_item">
<option value='None'>-</option>
<?php foreach(GameConst::$allItems['item'] as $itemID=>$cnt): ?>
<option value="<?=$itemID?>"><?=getItemName($itemID)?></option>
<?php endforeach; ?>
</select>
</div>
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">병종</span>
</div>
<select class="custom-select form_crewtype">
<?php foreach(GameUnitConst::all() as $crewTypeID => $crewType): ?>
<?php if($crewType->armType === GameUnitConst::T_CASTLE){ continue; } ?>
<option value="<?=$crewTypeID?>"><?=$crewType->name?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">병사</span>
</div>
<input type="number" class="form-control form_crew" value="7000" min="100" step="100">
<div class="input-group-prepend">
<span class="input-group-text">성격</span>
</div>
<select class="custom-select form_general_character">
<?php foreach(getCharacterList(false) as $characterID => [$name,$info]): ?>
<option value="<?=$characterID?>"><?=$name?></option>
<?php endforeach; ?>
</select>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">훈련</span>
</div>
<input type="number" class="form-control form_train" value="100" min="40" max="<?=GameConst::$maxTrainByWar?>" step="1">
<div class="input-group-prepend">
<span class="input-group-text">사기</span>
</div>
<input type="number" class="form-control form_atmos" value="100" min="40" max="<?=GameConst::$maxAtmosByWar?>" step="1">
<div class="input-group-prepend">
<span class="input-group-text">전특</span>
</div>
<select class="custom-select form_general_special_war">
<?php foreach(SpecialityHelper::getSpecialWarList(false) as $specialWarID =>$specialObj): ?>
<option value="<?=$specialWarID?>"><?=$specialObj->getName()?></option>
<?php endforeach; ?>
</select>
</div>
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">보병숙련</span>
</div>
<select class="custom-select form_dex1">
<?php foreach(getDexLevelList() as $dexLevel => [$dexAmount, $color, $name]): ?>
<option value="<?=$dexAmount?>"><?="{$name} (".number_format($dexAmount).")"?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">궁병숙련</span>
</div>
<select class="custom-select form_dex2">
<?php foreach(getDexLevelList() as $dexLevel => [$dexAmount, $color, $name]): ?>
<option value="<?=$dexAmount?>"><?="{$name} (".number_format($dexAmount).")"?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">기병숙련</span>
</div>
<select class="custom-select form_dex3">
<?php foreach(getDexLevelList() as $dexLevel => [$dexAmount, $color, $name]): ?>
<option value="<?=$dexAmount?>"><?="{$name} (".number_format($dexAmount).")"?></option>
<?php endforeach; ?>
</select>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">귀병숙련</span>
</div>
<select class="custom-select form_dex4">
<?php foreach(getDexLevelList() as $dexLevel => [$dexAmount, $color, $name]): ?>
<option value="<?=$dexAmount?>"><?="{$name} (".number_format($dexAmount).")"?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend">
<span class="input-group-text">차병숙련</span>
</div>
<select class="custom-select form_dex5">
<?php foreach(getDexLevelList() as $dexLevel => [$dexAmount, $color, $name]): ?>
<option value="<?=$dexAmount?>"><?="{$name} (".number_format($dexAmount).")"?></option>
<?php endforeach; ?>
</select>
<div class="input-group-prepend only_defender">
<span class="input-group-text">수비여부</span>
</div>
<select class="custom-select form_defence_train only_defender">
<option value="90">훈사 90</option>
<option value="80">훈사 80</option>
<option value="60">훈사 60</option>
<option value="40">훈사 40</option>
<option value="999">안함</option>
</select>
</div>
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">전투 </span>
</div>
<input type="number" class="form-control form_warnum" value="0" step="1">
<div class="input-group-prepend">
<span class="input-group-text">승리 </span>
</div>
<input type="number" class="form-control form_killnum" value="0" step="1">
<div class="input-group-prepend">
<span class="input-group-text">사살 </span>
</div>
<input type="number" class="form-control form_killcrew" value="0" step="1">
</div>
</div>
</div>
</div><!-- <div class="col-sm"> -->
</div>
<div class="card mb-3">
<div class="card-header">
전투 요약
</div>
<table class="table">
<tbody id="battle_result_summary">
<tr><th style='width:18ch;'>전투 일시</th><td id='result_datetime'></td></tr>
<tr><th>전투 횟수</th><td id='result_warcnt'></td></tr>
<tr><th>전투 페이즈</th><td id='result_phase'></td></tr>
<tr><th> 피해</th><td><span id='result_killed'>0</span><span id='result_varKilled'> (<span id='result_minKilled'>0</span> ~ <span id='result_maxKilled'>0</span>)</span></td></tr>
<tr><th>받은 피해</th><td><span id='result_dead'>0</span><span id='result_varDead'> (<span id='result_minDead'>0</span> ~ <span id='result_maxDead'>0</span>)</span></td></tr>
<tr><th>출병자 군량 소모</th><td id='result_attackerRice'></td></tr>
<tr><th>수비자 군량 소모</th><td id='result_defenderRice'></td></tr>
<tr><th>공격자 스킬</th><td id='result_attackerSkills'></td></tr>
<tr class='result_defenderSkills'><th>수비자1 스킬</th><td></td></tr>
</tbody>
</table>
</div>
<div class="row">
<div class="col-sm">
<div class="card mb-3">
<div class="card-header">
마지막 전투 로그
</div>
<div class="card-body" id="generalBattleResultLog">
</div>
</div>
</div>
<div class="col-sm">
<div class="card mb-3">
<div class="card-header">
마지막 전투 상세 로그
</div>
<div class="card-body" id="generalBattleDetailLog">
</div>
</div>
</div>
</div>
</div>
<div id="importModal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">장수 목록</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<select id="modalSelector"></select>
<p>타국 장수를 선택한 경우 숙련과 아이템은 0으로 초기화됩니다.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" id='importFromDB'>가져오기</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">닫기</button>
</div>
</div>
</div>
</div>
</body>
</html>
+1 -1
View File
@@ -49,6 +49,7 @@ if($btn == '참가') {
$general['gold'] -= $admin['develcost'];
$freeSlot = [
0=>8,
1=>8,
2=>8,
3=>8,
@@ -56,7 +57,6 @@ if($btn == '참가') {
5=>8,
6=>8,
7=>8,
8=>8,
];
foreach($db->query('SELECT count(*) as cnt, grp FROM tournament WHERE grp < 10 GROUP BY grp') as $grpInfo){
if($grpInfo['cnt'] == 8){
+155 -135
View File
@@ -1,40 +1,56 @@
@charset "UTF-8";
/* font-boostring Block */
html * {max-height:1000000px;}
html, body{
background-color:black;
color:white;
line-height:1.3;
font-family:'맑은 고딕';
font-size:13px;
html * {
max-height: 1000000px;
}
table { font-family:'맑은 고딕'; }
font { font-family:'맑은 고딕'; }
input { font-family:'맑은 고딕'; font-size:13px; }
select { font-family:'굴림'; line-height:100%; }
.center{
text-align:center;
html,
body {
background-color: black;
color: white;
line-height: 1.3;
font-family: '맑은 고딕';
font-size: 13px;
}
table.mimic_flex{
table {
font-family: '맑은 고딕';
}
font {
font-family: '맑은 고딕';
}
input {
font-family: '맑은 고딕';
font-size: 13px;
}
select {
font-family: '굴림';
line-height: 100%;
}
.center {
text-align: center;
}
table.mimic_flex {
border-collapse: collapse;
border:none;
padding:0;
border: none;
padding: 0;
}
.mimic_flex td, .mimic_flex th {
border:none !important;
.mimic_flex td,
.mimic_flex th {
border: none !important;
padding: 0px;
word-break: break-all;
}
table.tb_layout {
table.tb_layout {
border-collapse: collapse;
padding: 0px;
font-size: 13px;
@@ -42,159 +58,161 @@ table.tb_layout {
font-family: '맑은 고딕';
}
.tb_layout td, .tb_layout th {
border:solid 1px gray;
.tb_layout td,
.tb_layout th {
border: solid 1px gray;
padding: 0px;
word-break: break-all;
font-family: '맑은 고딕';;
font-family: '맑은 고딕';
;
}
div.bar_out{
position:relative;
border-top:solid 1px #888888;
border-bottom:solid 1px #333333;
padding:0;
margin:0;
width:100%;
div.bar_out {
position: relative;
border-top: solid 1px #888888;
border-bottom: solid 1px #333333;
padding: 0;
margin: 0;
width: 100%;
overflow: hidden;
}
div.bar_out div{
position:absolute;
left:0;
top:0;
height:100%;
div.bar_out div {
position: absolute;
left: 0;
top: 0;
height: 100%;
}
div.bar_out div.bar_in{
width:100%;
div.bar_out div.bar_in {
width: 100%;
}
/* */
.ev_warning{
color:orangered;
.ev_warning {
color: orangered;
}
.ev_notice{
color:orangered;
.ev_notice {
color: orangered;
}
.ev_succes{
color:lightgreen;
.ev_succes {
color: lightgreen;
}
.ev_sell{
color:orange;
.ev_sell {
color: orange;
}
.ev_failed{
color:orangered;
.ev_failed {
color: orangered;
}
.ev_highlight{
color:orangered;
.ev_highlight {
color: orangered;
}
/* TODO: 색상값이 아니라 의미에 따라 클래스 지정 */
.o_bullet::before{
color:cyan;
content:"●";
.o_bullet::before {
color: cyan;
content: "●";
}
.o_diamond::before{
color:orangered;
content:"◆";
.o_diamond::before {
color: orangered;
content: "◆";
}
.small_war_log{
display:inline-block;
.small_war_log {
display: inline-block;
}
.small_war_log .war_type_attack{
color:cyan;
.small_war_log .war_type_attack {
color: cyan;
}
.small_war_log .war_type_defense{
color:magenta;
.small_war_log .war_type_defense {
color: magenta;
}
.small_war_log .war_type_siege{
color:white;
.small_war_log .war_type_siege {
color: white;
}
.small_war_log .name_plate{
.small_war_log .name_plate {
font-size: 0.75em;
}
.small_war_log .name_plate_cover{
color:yellow;
.small_war_log .name_plate_cover {
color: yellow;
}
.small_war_log .crew_plate{
color:orangered;
font-size:90%;
.small_war_log .crew_plate {
color: orangered;
font-size: 90%;
}
.t_date{
.t_date {
font-size: 0.75em;
}
.t_red{
color:red;
.t_red {
color: red;
}
.t_blue{
color:blue;
.t_blue {
color: blue;
}
.t_green{
color:green;
.t_green {
color: green;
}
.t_magenta{
color:magenta;
.t_magenta {
color: magenta;
}
.t_cyan{
color:cyan;
.t_cyan {
color: cyan;
}
.t_limegreen{
color:limegreen;
.t_limegreen {
color: limegreen;
}
.t_skyblue{
color:skyblue;
.t_skyblue {
color: skyblue;
}
.t_orangered{
color:orangered;
.t_orangered {
color: orangered;
}
.t_yellow{
color:yellow;
.t_yellow {
color: yellow;
}
.t_white{
color:white;
.t_white {
color: white;
}
.float_left{
float:left;
.float_left {
float: left;
}
.tooltip{
font-size:12px;
.tooltip {
font-size: 12px;
font-family: '맑은 고딕';
}
.tooltip_copyable_info .tooltiptext{
.tooltip_copyable_info .tooltiptext {
display: inline;
color: rgba(0,0,0,0);
color: rgba(0, 0, 0, 0);
font-size: 0;
}
@@ -202,67 +220,69 @@ div.bar_out div.bar_in{
display: none;
}
.hidden_but_copyable{
color: rgba(0,0,0,0);
.hidden_but_copyable {
color: rgba(0, 0, 0, 0);
font-size: 0;
}
.btn-group-xs > .btn, .btn-xs {
padding : .25rem .4rem;
font-size : .875rem;
line-height : .5;
border-radius : .2rem;
.btn-group-xs>.btn,
.btn-xs {
padding: .25rem .4rem;
font-size: .875rem;
line-height: .5;
border-radius: .2rem;
}
.edit_form.viewer{
max-height:200px;
overflow-y:auto;
.edit_form.viewer {
max-height: 200px;
overflow-y: auto;
}
.trumbowyg-box{
margin:0;
border-left:none;
border-right:none;
.trumbowyg-box {
margin: 0;
border-left: none;
border-right: none;
}
.edit_form.trumbowyg-editor{
margin:0;
padding:0;
.edit_form.trumbowyg-editor {
margin: 0;
padding: 0;
}
.commandBasic{
background-color:black;
color:white;
.commandBasic {
background-color: black;
color: white;
}
.compensatePositive{
color:skyblue;
.compensatePositive {
color: skyblue;
}
.compensateNegative{
color:orange;
.compensateNegative {
color: orange;
}
.compensateNeutral{
color:white;
.compensateNeutral {
color: white;
}
.commandBasic.commandImpossible{
background-color:red;
color:white;
.commandBasic.commandImpossible {
background-color: red;
color: white;
}
.select2-selection--single.simple-select2-align-center .select2-selection__rendered {
text-align: center;
}
.select2-dropdown.simple-select2-align-center li.select2-results__option{
.select2-dropdown.simple-select2-align-center li.select2-results__option {
text-align: center;
}
.select2-container--bootstrap4 .select2-selection--single.text-secondary .select2-selection__rendered{
color:white;
.select2-container--bootstrap4 .select2-selection--single.text-secondary .select2-selection__rendered {
color: white;
}
.select2-container--bootstrap4 .text-secondary .select2-results__option[aria-selected=false]{
color:white;
}
.select2-container--bootstrap4 .text-secondary .select2-results__option[aria-selected=false] {
color: white;
}
+23
View File
@@ -0,0 +1,23 @@
#inheritance_list{
display: flex;
flex-wrap: wrap;
}
.inherit_padding{
width: 33%;
padding: 10px 2px;
}
.inherit_item{
width: 33%;
padding: 10px 2px;
}
.col-form-label{
text-align:right;
padding-right:2ch;
}
.inherit_value{
text-align: right;
}
+11
View File
@@ -0,0 +1,11 @@
#amount {
width: 100px;
}
#colorType {
width: 150px;
}
.no-padding .select2-results__option {
padding: 0;
}
+64
View File
@@ -0,0 +1,64 @@
@charset "UTF-8";
.container {
width: 1000px;
margin: 0 auto;
}
.card_holder {
text-align: center;
}
.general_card {
width: 125px;
display: inline-block;
}
.general_card h4 {
margin: 0;
}
.general_card p {
margin: 0;
}
.general_card .select_btn {
width: 100%;
}
.general_card label {
display: block;
padding-left: 15px;
text-indent: -15px;
}
.general_card input {
width: 13px;
height: 13px;
padding: 0;
margin: 0;
vertical-align: bottom;
position: relative;
top: -1px;
*overflow: hidden;
}
#outdate_token {
color: red;
display: none;
}
#left_pad button {
display: none;
}
.custom_picture {
display: none;
}
.custom_personality {
display: none;
}
.custom_stat {
display: none;
}
+2178 -2105
View File
File diff suppressed because it is too large Load Diff
+447 -447
View File
@@ -1,448 +1,448 @@
<?php
namespace sammo;
use sammo\Command\GeneralCommand;
use sammo\Command\NationCommand;
function getGeneralTurnBrief(General $generalObj, array $turnList) {
$result = [];
foreach($turnList as $turnIdx => [$action, $arg]){
$commandObj = buildGeneralCommandClass($action, $generalObj, [], $arg);
$turnText = $commandObj->getBrief();
$result[$turnIdx] = $turnText;
}
return $result;
}
function getNationTurnBrief(General $generalObj, array $turnList) {
$result = [];
$tmpTurn = new LastTurn();
foreach($turnList as $turnIdx => [$action, $arg]){
$commandObj = buildNationCommandClass($action, $generalObj, [], $tmpTurn, $arg);
$turnText = $commandObj->getBrief();
$result[$turnIdx] = $turnText;
}
return $result;
}
function pushGeneralCommand(int $generalID, int $turnCnt=1){
if($turnCnt == 0){
return;
}
if($turnCnt < 0){
pullGeneralCommand($generalID, -$turnCnt);
return;
}
if($turnCnt >= GameConst::$maxTurn){
return;
}
$db = DB::db();
$db->update('general_turn', [
'turn_idx'=>$db->sqleval('turn_idx + %i', $turnCnt)
], 'general_id=%i ORDER BY turn_idx DESC', $generalID);
$db->update('general_turn', [
'turn_idx'=>$db->sqleval('turn_idx - %i', GameConst::$maxTurn),
'action'=>'휴식',
'arg'=>'{}',
'brief'=>'휴식'
], 'general_id=%i AND turn_idx >= %i', $generalID, GameConst::$maxTurn);
}
function pullGeneralCommand(int $generalID, int $turnCnt=1){
if($turnCnt == 0){
return;
}
if($turnCnt < 0){
pushGeneralCommand($generalID, -$turnCnt);
return;
}
if($turnCnt >= GameConst::$maxTurn){
return;
}
$db = DB::db();
$db->update('general_turn', [
'turn_idx'=>$db->sqleval('turn_idx + %i', GameConst::$maxTurn),
'action'=>'휴식',
'arg'=>'{}',
'brief'=>'휴식'
], 'general_id=%i AND turn_idx < %i', $generalID, $turnCnt);
$db->update('general_turn', [
'turn_idx'=>$db->sqleval('turn_idx - %i', $turnCnt)
], 'general_id=%i ORDER BY turn_idx ASC', $generalID);
}
function repeatGeneralCommand(int $generalId, int $turnCnt){
if($turnCnt <= 0){
return;
}
if($turnCnt >= GameConst::$maxTurn){
return;
}
$db = DB::db();
$reqTurn = $turnCnt;
if($turnCnt * 2 > GameConst::$maxTurn){
$reqTurn = GameConst::$maxTurn - $turnCnt;
}
$turnList = $db->query('SELECT turn_idx, `action`, arg, brief FROM general_turn WHERE general_id=%i AND turn_idx < %i', $generalId, $reqTurn);
foreach($turnList as $turnItem){
$turnIdx = $turnItem['turn_idx'];
$turnTarget = iterator_to_array(Util::range($turnIdx+$turnCnt, GameConst::$maxTurn, $turnCnt));
$db->update('general_turn', [
'action'=>$turnItem['action'],
'arg'=>$turnItem['arg'],
'brief'=>$turnItem['brief']
], 'general_id=%i AND turn_idx IN %li', $generalId, $turnTarget);
}
}
function pushNationCommand(int $nationID, int $officerLevel, int $turnCnt=1){
if($nationID == 0){
return;
}
if($officerLevel < 5){
return;
}
if($turnCnt == 0){
return;
}
if($turnCnt < 0){
pullNationCommand($nationID, $officerLevel, -$turnCnt);
return;
}
if($turnCnt >= GameConst::$maxChiefTurn){
return;
}
$db = DB::db();
$db->update('nation_turn', [
'turn_idx'=>$db->sqleval('turn_idx + %i', $turnCnt)
], 'nation_id=%i AND officer_level=%i ORDER BY turn_idx DESC', $nationID, $officerLevel);
$db->update('nation_turn', [
'turn_idx'=>$db->sqleval('turn_idx - %i', GameConst::$maxChiefTurn),
'action'=>'휴식',
'arg'=>'{}',
'brief'=>'휴식'
], 'nation_id=%i AND officer_level=%i AND turn_idx >= %i ORDER BY turn_idx ASC', $nationID, $officerLevel, GameConst::$maxChiefTurn);
}
function pullNationCommand(int $nationID, int $officerLevel, int $turnCnt=1){
if($nationID == 0){
return;
}
if($officerLevel < 5){
return;
}
if($turnCnt == 0){
return;
}
if($turnCnt < 0){
pushNationCommand($nationID, $officerLevel, -$turnCnt);
return;
}
if($turnCnt >= GameConst::$maxChiefTurn){
return;
}
$db = DB::db();
$db->update('nation_turn', [
'turn_idx'=>$db->sqleval('turn_idx + %i', GameConst::$maxChiefTurn),
'action'=>'휴식',
'arg'=>'{}',
'brief'=>'휴식',
], 'nation_id=%i AND officer_level=%i AND turn_idx < %i', $nationID, $officerLevel, $turnCnt);
$db->update('nation_turn', [
'turn_idx'=>$db->sqleval('turn_idx - %i', $turnCnt)
], 'nation_id=%i AND officer_level=%i ORDER BY turn_idx ASC', $nationID, $officerLevel);
}
function _setGeneralCommand(GeneralCommand $command, array $turnList):void {
if(!$turnList){
return;
}
$db = DB::db();
$generalID = $command->getGeneral()->getID();
$commandName = $command->getRawClassName();
$arg = $command->getArg();
$brief = $command->getBrief();
$db->update('general_turn', [
'action'=>$commandName,
'arg'=>Json::encode($arg, JSON::EMPTY_ARRAY_IS_DICT),
'brief'=>$brief
], 'general_id = %i AND turn_idx IN %li', $generalID, $turnList);
}
function _setNationCommand(NationCommand $command, array $turnList):void {
if(!$turnList){
return;
}
$db = DB::db();
$nationID = $command->getNationID();
$officerLevel = $command->getOfficerLevel();
$commandName = $command->getRawClassName();
$arg = $command->getArg();
$brief = $command->getBrief();
$db->update('nation_turn', [
'action'=>$commandName,
'arg'=>Json::encode($arg, JSON::EMPTY_ARRAY_IS_DICT),
'brief'=>$brief
], 'nation_id = %i AND officer_level = %i AND turn_idx IN %li', $nationID, $officerLevel, $turnList);
}
function sanitizeArg(?array $args):?array{
if($args === null){
return $args;
}
$result = [];
foreach($args as $key=>$value){
if(is_array($value)){
$result[$key] = sanitizeArg($value);
}
else if(is_string($value)){
$result[$key] = StringUtil::neutralize(StringUtil::removeSpecialCharacter($value));
}
else{
$result[$key] = $value;
}
}
return $result;
}
function checkCommandArg(?array $arg):?string{
if($arg === null){
return null;
}
$defaultCheck = [
/*'string'=>[
'nationName', 'optionText', 'itemType', 'nationType'
],*/
'integer'=>[
'crewType', 'destGeneralID', 'destCityID', 'destNationID',
'amount', 'colorType',
'srcArmType', 'destArmType', //숙련전환 전용
],
'boolean'=>[
'isGold', 'buyRice',
],
'between'=>[
['month', [1, 12]]
],
'min'=>[
['year', 0],
['destGeneralID', 1],
['destCityID', 1],
['destNationID', 1],
['amount', 1],
['crewType', 0]
],
'integerArray'=>[
'destNationIDList', 'destGeneralIDList', 'amountList'
],
'stringWidthBetween'=>[
['nationName', 1, 18]
]
];
$v = new Validator($arg);
$v->rules($defaultCheck);
if (!$v->validate()){
return $v->errorStr();
}
return null;
}
function setGeneralCommand(int $generalID, array $rawTurnList, string $command, ?array $arg = null):array{
$turnList = [];
foreach($rawTurnList as $turnIdx){
if(!is_int($turnIdx) || $turnIdx < -3 || $turnIdx >= GameConst::$maxTurn){
return [
'result'=>false,
'reason'=>'올바른 턴이 아닙니다. : '.$turnIdx,
'test'=>'turnIdx',
'target'=>$turnIdx,
];
}
if($turnIdx >= 0){
$turnList[$turnIdx] = true;
}
else if($turnIdx == -1){
//홀수
foreach(Util::range(1, GameConst::$maxTurn, 2) as $subIdx){
$turnList[$subIdx] = true;
}
}
else if($turnIdx == -2){
//짝수
foreach(Util::range(0, GameConst::$maxTurn, 2) as $subIdx){
$turnList[$subIdx] = true;
}
}
else if($turnIdx == -3){
//모두
foreach(Util::range(GameConst::$maxTurn) as $subIdx){
$turnList[$subIdx] = true;
}
}
}
$turnList = array_keys($turnList);
$arg = sanitizeArg($arg);
$argBasicTestResult = checkCommandArg($arg);
if($argBasicTestResult !== null){
return [
'result'=>false,
'reason'=>'턴이 입력되지 않았습니다.',
'test'=>'checkCommandArg',
'target'=>'arg'
];
}
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$env = $gameStor->getAll();
$general = General::createGeneralObjFromDB($generalID);
try{
$commandObj = buildGeneralCommandClass($command, $general, $env, $arg);
}
catch (\InvalidArgumentException $e){
return [
'result'=>false,
'reason'=>$e->getMessage(),
'test'=>'build',
'target'=>'arg'
];
}
catch (\Exception $e){
return [
'result'=>false,
'reason'=>$e->getCode().$e->getMessage(),
'test'=>'build',
'target'=>'arg'
];
}
if(!$commandObj->isArgValid()){
return [
'result'=>false,
'reason'=>'올바르지 않은 argument',
'test'=>'isArgValid',
'target'=>'arg'
];
}
if(!$commandObj->hasPermissionToReserve()){
return [
'result'=>false,
'reason'=>'예약 불가능한 커맨드 :'.$commandObj->testPermissionToReserve(),
'test'=>'hasPermissionToReserve',
'target'=>'command'
];
}
_setGeneralCommand($commandObj, $turnList);
return [
'result'=>true,
'reason'=>'success'
];
}
function setNationCommand(int $generalID, array $turnList, string $command, ?array $arg = null):array{
$turnList = array_unique($turnList);
foreach($turnList as $turnIdx){
if(!is_int($turnIdx) || $turnIdx < 0 || $turnIdx >= GameConst::$maxChiefTurn){
return [
'result'=>false,
'reason'=>'올바른 턴이 아닙니다. : '.$turnIdx,
'test'=>'turnIdx',
'target'=>$turnIdx,
];
}
}
$arg = sanitizeArg($arg);
$argBasicTestResult = checkCommandArg($arg);
if($argBasicTestResult !== null){
return [
'result'=>false,
'reason'=>'턴이 입력되지 않았습니다.',
'test'=>'checkCommandArg',
'target'=>'arg'
];
}
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$env = $gameStor->getAll();
$general = General::createGeneralObjFromDB($generalID);
if($general->getVar('officer_level') < 5){
return [
'result'=>false,
'reason'=>'수뇌가 아닙니다'
];
}
try{
$commandObj = buildNationCommandClass($command, $general, $env, $general->getLastTurn(), $arg);
}
catch (\InvalidArgumentException $e){
return [
'result'=>false,
'reason'=>$e->getMessage(),
'test'=>'build',
'target'=>'arg'
];
}
catch (\Exception $e){
return [
'result'=>false,
'reason'=>$e->getCode().$e->getMessage(),
'test'=>'build',
'target'=>'arg'
];
}
if(!$commandObj->isArgValid()){
return [
'result'=>false,
'reason'=>'올바르지 않은 argument',
'test'=>'isArgValid',
'target'=>'arg'
];
}
if(!$commandObj->hasPermissionToReserve()){
return [
'result'=>false,
'reason'=>'예약 불가능한 커맨드 :'.$commandObj->testPermissionToReserve(),
'test'=>'hasPermissionToReserve',
'target'=>'command'
];
}
_setNationCommand($commandObj, $turnList);
return [
'result'=>true,
'arg_test'=>true,
'reason'=>'success'
];
<?php
namespace sammo;
use sammo\Command\GeneralCommand;
use sammo\Command\NationCommand;
function getGeneralTurnBrief(General $generalObj, array $turnList) {
$result = [];
foreach($turnList as $turnIdx => [$action, $arg]){
$commandObj = buildGeneralCommandClass($action, $generalObj, [], $arg);
$turnText = $commandObj->getBrief();
$result[$turnIdx] = $turnText;
}
return $result;
}
function getNationTurnBrief(General $generalObj, array $turnList) {
$result = [];
$tmpTurn = new LastTurn();
foreach($turnList as $turnIdx => [$action, $arg]){
$commandObj = buildNationCommandClass($action, $generalObj, [], $tmpTurn, $arg);
$turnText = $commandObj->getBrief();
$result[$turnIdx] = $turnText;
}
return $result;
}
function pushGeneralCommand(int $generalID, int $turnCnt=1){
if($turnCnt == 0){
return;
}
if($turnCnt < 0){
pullGeneralCommand($generalID, -$turnCnt);
return;
}
if($turnCnt >= GameConst::$maxTurn){
return;
}
$db = DB::db();
$db->update('general_turn', [
'turn_idx'=>$db->sqleval('turn_idx + %i', $turnCnt)
], 'general_id=%i ORDER BY turn_idx DESC', $generalID);
$db->update('general_turn', [
'turn_idx'=>$db->sqleval('turn_idx - %i', GameConst::$maxTurn),
'action'=>'휴식',
'arg'=>'{}',
'brief'=>'휴식'
], 'general_id=%i AND turn_idx >= %i', $generalID, GameConst::$maxTurn);
}
function pullGeneralCommand(int $generalID, int $turnCnt=1){
if($turnCnt == 0){
return;
}
if($turnCnt < 0){
pushGeneralCommand($generalID, -$turnCnt);
return;
}
if($turnCnt >= GameConst::$maxTurn){
return;
}
$db = DB::db();
$db->update('general_turn', [
'turn_idx'=>$db->sqleval('turn_idx + %i', GameConst::$maxTurn),
'action'=>'휴식',
'arg'=>'{}',
'brief'=>'휴식'
], 'general_id=%i AND turn_idx < %i', $generalID, $turnCnt);
$db->update('general_turn', [
'turn_idx'=>$db->sqleval('turn_idx - %i', $turnCnt)
], 'general_id=%i ORDER BY turn_idx ASC', $generalID);
}
function repeatGeneralCommand(int $generalId, int $turnCnt){
if($turnCnt <= 0){
return;
}
if($turnCnt >= GameConst::$maxTurn){
return;
}
$db = DB::db();
$reqTurn = $turnCnt;
if($turnCnt * 2 > GameConst::$maxTurn){
$reqTurn = GameConst::$maxTurn - $turnCnt;
}
$turnList = $db->query('SELECT turn_idx, `action`, arg, brief FROM general_turn WHERE general_id=%i AND turn_idx < %i', $generalId, $reqTurn);
foreach($turnList as $turnItem){
$turnIdx = $turnItem['turn_idx'];
$turnTarget = iterator_to_array(Util::range($turnIdx+$turnCnt, GameConst::$maxTurn, $turnCnt));
$db->update('general_turn', [
'action'=>$turnItem['action'],
'arg'=>$turnItem['arg'],
'brief'=>$turnItem['brief']
], 'general_id=%i AND turn_idx IN %li', $generalId, $turnTarget);
}
}
function pushNationCommand(int $nationID, int $officerLevel, int $turnCnt=1){
if($nationID == 0){
return;
}
if($officerLevel < 5){
return;
}
if($turnCnt == 0){
return;
}
if($turnCnt < 0){
pullNationCommand($nationID, $officerLevel, -$turnCnt);
return;
}
if($turnCnt >= GameConst::$maxChiefTurn){
return;
}
$db = DB::db();
$db->update('nation_turn', [
'turn_idx'=>$db->sqleval('turn_idx + %i', $turnCnt)
], 'nation_id=%i AND officer_level=%i ORDER BY turn_idx DESC', $nationID, $officerLevel);
$db->update('nation_turn', [
'turn_idx'=>$db->sqleval('turn_idx - %i', GameConst::$maxChiefTurn),
'action'=>'휴식',
'arg'=>'{}',
'brief'=>'휴식'
], 'nation_id=%i AND officer_level=%i AND turn_idx >= %i ORDER BY turn_idx ASC', $nationID, $officerLevel, GameConst::$maxChiefTurn);
}
function pullNationCommand(int $nationID, int $officerLevel, int $turnCnt=1){
if($nationID == 0){
return;
}
if($officerLevel < 5){
return;
}
if($turnCnt == 0){
return;
}
if($turnCnt < 0){
pushNationCommand($nationID, $officerLevel, -$turnCnt);
return;
}
if($turnCnt >= GameConst::$maxChiefTurn){
return;
}
$db = DB::db();
$db->update('nation_turn', [
'turn_idx'=>$db->sqleval('turn_idx + %i', GameConst::$maxChiefTurn),
'action'=>'휴식',
'arg'=>'{}',
'brief'=>'휴식',
], 'nation_id=%i AND officer_level=%i AND turn_idx < %i', $nationID, $officerLevel, $turnCnt);
$db->update('nation_turn', [
'turn_idx'=>$db->sqleval('turn_idx - %i', $turnCnt)
], 'nation_id=%i AND officer_level=%i ORDER BY turn_idx ASC', $nationID, $officerLevel);
}
function _setGeneralCommand(GeneralCommand $command, array $turnList):void {
if(!$turnList){
return;
}
$db = DB::db();
$generalID = $command->getGeneral()->getID();
$commandName = $command->getRawClassName();
$arg = $command->getArg();
$brief = $command->getBrief();
$db->update('general_turn', [
'action'=>$commandName,
'arg'=>Json::encode($arg, JSON::EMPTY_ARRAY_IS_DICT),
'brief'=>$brief
], 'general_id = %i AND turn_idx IN %li', $generalID, $turnList);
}
function _setNationCommand(NationCommand $command, array $turnList):void {
if(!$turnList){
return;
}
$db = DB::db();
$nationID = $command->getNationID();
$officerLevel = $command->getOfficerLevel();
$commandName = $command->getRawClassName();
$arg = $command->getArg();
$brief = $command->getBrief();
$db->update('nation_turn', [
'action'=>$commandName,
'arg'=>Json::encode($arg, JSON::EMPTY_ARRAY_IS_DICT),
'brief'=>$brief
], 'nation_id = %i AND officer_level = %i AND turn_idx IN %li', $nationID, $officerLevel, $turnList);
}
function sanitizeArg(?array $args):?array{
if($args === null){
return $args;
}
$result = [];
foreach($args as $key=>$value){
if(is_array($value)){
$result[$key] = sanitizeArg($value);
}
else if(is_string($value)){
$result[$key] = StringUtil::neutralize(StringUtil::removeSpecialCharacter($value));
}
else{
$result[$key] = $value;
}
}
return $result;
}
function checkCommandArg(?array $arg):?string{
if($arg === null){
return null;
}
$defaultCheck = [
/*'string'=>[
'nationName', 'optionText', 'itemType', 'nationType', 'commandType',
],*/
'integer'=>[
'crewType', 'destGeneralID', 'destCityID', 'destNationID',
'amount', 'colorType',
'srcArmType', 'destArmType', //숙련전환 전용
],
'boolean'=>[
'isGold', 'buyRice',
],
'between'=>[
['month', [1, 12]]
],
'min'=>[
['year', 0],
['destGeneralID', 1],
['destCityID', 1],
['destNationID', 1],
['amount', 1],
['crewType', 0]
],
'integerArray'=>[
'destNationIDList', 'destGeneralIDList', 'amountList'
],
'stringWidthBetween'=>[
['nationName', 1, 18]
]
];
$v = new Validator($arg);
$v->rules($defaultCheck);
if (!$v->validate()){
return $v->errorStr();
}
return null;
}
function setGeneralCommand(int $generalID, array $rawTurnList, string $command, ?array $arg = null):array{
$turnList = [];
foreach($rawTurnList as $turnIdx){
if(!is_int($turnIdx) || $turnIdx < -3 || $turnIdx >= GameConst::$maxTurn){
return [
'result'=>false,
'reason'=>'올바른 턴이 아닙니다. : '.$turnIdx,
'test'=>'turnIdx',
'target'=>$turnIdx,
];
}
if($turnIdx >= 0){
$turnList[$turnIdx] = true;
}
else if($turnIdx == -1){
//홀수, 0부터 맞다.
foreach(Util::range(0, GameConst::$maxTurn, 2) as $subIdx){
$turnList[$subIdx] = true;
}
}
else if($turnIdx == -2){
//짝수, 1부터 맞다.
foreach(Util::range(1, GameConst::$maxTurn, 2) as $subIdx){
$turnList[$subIdx] = true;
}
}
else if($turnIdx == -3){
//모두
foreach(Util::range(GameConst::$maxTurn) as $subIdx){
$turnList[$subIdx] = true;
}
}
}
$turnList = array_keys($turnList);
$arg = sanitizeArg($arg);
$argBasicTestResult = checkCommandArg($arg);
if($argBasicTestResult !== null){
return [
'result'=>false,
'reason'=>'턴이 입력되지 않았습니다.',
'test'=>'checkCommandArg',
'target'=>'arg'
];
}
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$env = $gameStor->getAll();
$general = General::createGeneralObjFromDB($generalID);
try{
$commandObj = buildGeneralCommandClass($command, $general, $env, $arg);
}
catch (\InvalidArgumentException $e){
return [
'result'=>false,
'reason'=>$e->getMessage(),
'test'=>'build',
'target'=>'arg'
];
}
catch (\Exception $e){
return [
'result'=>false,
'reason'=>$e->getCode().$e->getMessage(),
'test'=>'build',
'target'=>'arg'
];
}
if(!$commandObj->isArgValid()){
return [
'result'=>false,
'reason'=>'올바르지 않은 argument',
'test'=>'isArgValid',
'target'=>'arg'
];
}
if(!$commandObj->hasPermissionToReserve()){
return [
'result'=>false,
'reason'=>'예약 불가능한 커맨드 :'.$commandObj->testPermissionToReserve(),
'test'=>'hasPermissionToReserve',
'target'=>'command'
];
}
_setGeneralCommand($commandObj, $turnList);
return [
'result'=>true,
'reason'=>'success'
];
}
function setNationCommand(int $generalID, array $turnList, string $command, ?array $arg = null):array{
$turnList = array_unique($turnList);
foreach($turnList as $turnIdx){
if(!is_int($turnIdx) || $turnIdx < 0 || $turnIdx >= GameConst::$maxChiefTurn){
return [
'result'=>false,
'reason'=>'올바른 턴이 아닙니다. : '.$turnIdx,
'test'=>'turnIdx',
'target'=>$turnIdx,
];
}
}
$arg = sanitizeArg($arg);
$argBasicTestResult = checkCommandArg($arg);
if($argBasicTestResult !== null){
return [
'result'=>false,
'reason'=>'턴이 입력되지 않았습니다.',
'test'=>'checkCommandArg',
'target'=>'arg'
];
}
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$env = $gameStor->getAll();
$general = General::createGeneralObjFromDB($generalID);
if($general->getVar('officer_level') < 5){
return [
'result'=>false,
'reason'=>'수뇌가 아닙니다'
];
}
try{
$commandObj = buildNationCommandClass($command, $general, $env, $general->getLastTurn(), $arg);
}
catch (\InvalidArgumentException $e){
return [
'result'=>false,
'reason'=>$e->getMessage(),
'test'=>'build',
'target'=>'arg'
];
}
catch (\Exception $e){
return [
'result'=>false,
'reason'=>$e->getCode().$e->getMessage(),
'test'=>'build',
'target'=>'arg'
];
}
if(!$commandObj->isArgValid()){
return [
'result'=>false,
'reason'=>'올바르지 않은 argument',
'test'=>'isArgValid',
'target'=>'arg'
];
}
if(!$commandObj->hasPermissionToReserve()){
return [
'result'=>false,
'reason'=>'예약 불가능한 커맨드 :'.$commandObj->testPermissionToReserve(),
'test'=>'hasPermissionToReserve',
'target'=>'command'
];
}
_setNationCommand($commandObj, $turnList);
return [
'result'=>true,
'arg_test'=>true,
'reason'=>'success'
];
}
+24
View File
@@ -378,6 +378,30 @@ function buildWarUnitTriggerClass(?string $type, WarUnit $unit, ?array $args = n
return $class->newInstanceArgs(array_merge([$unit], $args));
}
function getGeneralPoolClass(string $type){
static $basePath = __NAMESPACE__.'\\GeneralPool\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 GeneralPool이 아님");
}
/**
* @param \MeekroDB $db
* @param int $owner
* @param int $pickCnt
* @param null|string $prefix
* @return AbsGeneralPool[]
*/
function pickGeneralFromPool(\MeekroDB $db, int $owner, int $pickCnt, ?string $prefix=null):array{
/** @var AbsGeneralPool */
$class = getGeneralPoolClass(GameConst::$targetGeneralPool);
return $class::pickGeneralFromPool($db, $owner, $pickCnt, $prefix);
}
function countPureGeneralFromRawList(?array $rawGeneralList=null):int{
if(!$rawGeneralList){
return 0;
+1173 -1136
View File
@@ -1,1136 +1,1173 @@
<?php
namespace sammo;
use Monolog\Logger;
/**
* 게임 룰에 해당하는 함수 모음
*/
function getNationLevelList(): array
{
$table = [
0 => ['방랑군', 2, 0],
1 => ['호족', 2, 1],
2 => ['군벌', 4, 2],
3 => ['주자사', 4, 5],
4 => ['주목', 6, 8],
5 => ['공', 6, 11],
6 => ['왕', 8, 16],
7 => ['황제', 8, 21],
];
return $table;
}
function getCityLevelList(): array
{
return [
1 => '수',
2 => '진',
3 => '관',
4 => '이',
5 => '소',
6 => '중',
7 => '대',
8 => '특'
];
}
//한국가의 전체 전방 설정
function SetNationFront($nationNo)
{
if (!$nationNo) {
return;
}
// 도시소유 국가와 선포,교전중인 국가
$adj3 = [];
$adj2 = [];
$adj1 = [];
$db = DB::db();
foreach ($db->queryFirstColumn(
'SELECT city FROM city JOIN diplomacy ON diplomacy.you = city.nation WHERE diplomacy.state = 0 AND me = %i',
$nationNo
) as $city) {
foreach (CityConst::byID($city)->path as $adjKey => $adjVal) {
$adj3[$adjKey] = $adjVal;
}
};
foreach ($db->queryFirstColumn(
'SELECT city FROM city JOIN diplomacy ON diplomacy.you = city.nation WHERE diplomacy.state = 1 AND diplomacy.term <= 5 AND me = %i',
$nationNo
) as $city) {
foreach (CityConst::byID($city)->path as $adjKey => $adjVal) {
$adj1[$adjKey] = $adjVal;
}
}
if (!$adj3 && !$adj1) {
//평시이면 공백지
//NOTE: if, else일 경우 NPC는 전쟁시에는 공백지로 출병하지 않는다는 뜻이 된다.
foreach ($db->queryFirstColumn('SELECT city from city where nation=0') as $city) {
foreach (CityConst::byID($city)->path as $adjKey => $adjVal) {
$adj2[$adjKey] = $adjVal;
}
}
}
$db->update('city', [
'front' => 0
], 'nation=%i', $nationNo);
if ($adj1) {
$db->update('city', [
'front' => 1,
], 'nation=%i and city in %li', $nationNo, array_keys($adj1));
}
if ($adj2) {
$db->update('city', [
'front' => 2,
], 'nation=%i and city in %li', $nationNo, array_keys($adj2));
}
if ($adj3) {
$db->update('city', [
'front' => 3,
], 'nation=%i and city in %li', $nationNo, array_keys($adj3));
}
}
function checkSupply()
{
$db = DB::db();
$cities = [];
foreach ($db->query('SELECT city, nation FROM city WHERE nation != 0') as $city) {
$newCity = new \stdClass();
$newCity->id = Util::toInt($city['city']);
$newCity->nation = Util::toInt($city['nation']);
$newCity->supply = false;
$cities[$newCity->id] = $newCity;
}
$queue = new \SplQueue();
foreach ($db->queryAllLists('SELECT capital, nation FROM nation WHERE `level` > 0') as list($capitalID, $nationID)) {
if (!key_exists($capitalID, $cities)) {
continue;
}
$city = $cities[$capitalID];
if ($nationID != $city->nation) {
continue;
}
$city->supply = true;
$queue->enqueue($city);
}
while (!$queue->isEmpty()) {
$cityLink = $queue->dequeue();
$city = CityConst::byID($cityLink->id);
foreach (array_keys($city->path) as $connCityID) {
if (!key_exists($connCityID, $cities)) {
continue;
}
$connCity = $cities[$connCityID];
if ($connCity->nation != $cityLink->nation) {
continue;
}
if ($connCity->supply) {
continue;
}
$connCity->supply = true;
$queue->enqueue($connCity);
}
}
$db->update('city', [
'supply' => 1
], 'nation=0');
$db->update('city', [
'supply' => 0
], 'nation!=0');
$supply = [];
foreach ($cities as $city) {
if ($city->supply) {
$supply[] = $city->id;
}
}
if ($supply) {
$db->update('city', [
'supply' => 1
], 'city IN %li', $supply);
}
}
function updateGeneralNumber(){
$db = DB::db();
foreach($db->queryAllLists('SELECT nation, count(*) FROM general WHERE npc != 5 GROUP BY nation') as [$nationID, $gennum]){
if($nationID === 0){
continue;
}
$db->update('nation', [
'gennum'=>$gennum
], 'nation=%i', $nationID);
}
refreshNationStaticInfo();
}
function updateYearly()
{
//통계
checkStatistic();
}
//관직 변경 해제
function updateQuaterly()
{
$db = DB::db();
//천도 제한 해제, 관직 변경 제한 해제
$db->update('nation', [
'chief_set' => 0,
], true);
//관직 변경 제한 해제
$db->update('city', [
'officer_set' => 0,
], true);
}
// 벌점 감소와 건국제한-1 전턴제한-1 외교제한-1, 1달마다 실행, 병사 있는 장수의 군량 감소, 수입비율 조정
function preUpdateMonthly()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
//연감 월결산
$result = LogHistory();
if ($result == false) {
return false;
}
$admin = $gameStor->getValues(['startyear', 'year', 'month']);
$logger = new ActionLogger(0, 0, $admin['year'], $admin['month']);
//보급선 체크
checkSupply();
//미보급도시 10% 감소
$db->update('city', [
'pop' => $db->sqleval('pop * 0.9'),
'trust' => $db->sqleval('trust * 0.9'),
'agri' => $db->sqleval('agri * 0.9'),
'comm' => $db->sqleval('comm * 0.9'),
'secu' => $db->sqleval('secu * 0.9'),
'def' => $db->sqleval('def * 0.9'),
'wall' => $db->sqleval('wall * 0.9'),
], 'supply = 0');
//미보급도시 장수 병 훈 사 5%감소
//NOTE: update inner join도 가능하지만, meekrodb 기준으로 깔끔하게.
$unsuppliedCities = $db->query('SELECT city, nation, trust, name FROM city WHERE supply = 0');
foreach (Util::arrayGroupBy($unsuppliedCities, 'nation') as $nationID => $cityList) {
$cityIDList = Util::squeezeFromArray($cityList, 'city');
$db->update('general', [
'crew' => $db->sqleval('crew*0.95'),
'atmos' => $db->sqleval('atmos*0.95'),
'train' => $db->sqleval('train*0.95'),
], 'city IN %li AND nation = %i', $cityIDList, $nationID);
}
//민심30이하 공백지 처리
$lostCities = [];
foreach ($unsuppliedCities as $unsuppliedCity) {
if ($unsuppliedCity['trust'] >= 30) {
continue;
}
$lostCities[$unsuppliedCity['city']] = $unsuppliedCity;
}
if ($lostCities) {
foreach ($lostCities as $lostCity) {
$josaYi = JosaUtil::pick($lostCity['name'], '이');
$logger->pushGlobalHistoryLog("<R><b>【고립】</b></><G><b>{$lostCity['name']}</b></>{$josaYi} 보급이 끊겨 <R>미지배</> 도시가 되었습니다.");
}
$db->update('general', [
'officer_level' => 1,
'officer_city' => 0
], 'officer_city IN %li', array_keys($lostCities));
$db->update('city', [
'nation' => 0,
'officer_set' => 0,
'conflict' => '{}',
'term' => 0,
'front' => 0
], 'city IN %li', array_keys($lostCities));
}
//접률감소, 건국제한-1
$db->update('general', [
'connect' => $db->sqleval('floor(connect*0.99)'),
'makelimit' => $db->sqleval('greatest(0, makelimit - 1)'),
], true);
//전략제한-1, 외교제한-1, 세율동기화
$db->update('nation', [
'strategic_cmd_limit' => $db->sqleval('greatest(0, strategic_cmd_limit - 1)'),
'surlimit' => $db->sqleval('greatest(0, surlimit - 1)'),
'rate_tmp' => $db->sqleval('rate')
], true);
//도시훈사 180년 60, 220년 87, 240년 100
$rate = Util::round(($admin['year'] - $admin['startyear']) / 1.5) + 60;
if ($rate > 100) $rate = 100;
// 20 ~ 140원
$develcost = ($admin['year'] - $admin['startyear'] + 10) * 2;
$gameStor->city_rate = $rate;
$gameStor->develcost = $develcost;
//매달 사망자 수입 결산
processWarIncome();
//계략, 전쟁표시 해제
$db->update('city', [
'state' => $db->sqleval(<<<EOD
(CASE
WHEN state=31 THEN 0
WHEN state=32 THEN 31
WHEN state=33 THEN 0
WHEN state=34 THEN 33
WHEN state=41 THEN 0
WHEN state=42 THEN 41
WHEN state=43 THEN 42
ELSE state END)
EOD),
'term' => $db->sqleval('greatest(0, term - 1)'),
'conflict' => $db->sqleval('if(term = 0,%s,conflict)', '{}'),
], true);
//첩보-1
foreach ($db->queryAllLists("SELECT nation, spy FROM nation WHERE spy!='' AND spy!='{}'") as [$nationNo, $rawSpy]) {
$spyInfo = Json::decode($rawSpy);
foreach ($spyInfo as $cityNo => $remainMonth) {
if ($remainMonth <= 1) {
unset($spyInfo[$cityNo]);
} else {
$spyInfo[$cityNo] -= 1;
}
}
$db->update('nation', [
'spy' => Json::encode($spyInfo, Json::EMPTY_ARRAY_IS_DICT)
], 'nation=%i', $nationNo);
}
return true;
}
// 외교 로그처리, 외교 상태 처리
function postUpdateMonthly()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['startyear', 'year', 'month', 'scenario']);
$globalLogger = new ActionLogger(0, 0, $admin['year'], $admin['month']);
//도시 수 측정
$cityNations = [];
foreach ($db->queryAllLists('SELECT city, name, nation FROM city') as [$cityID, $cityName, $cityNation]) {
if (!key_exists($cityNation, $cityNations)) {
$cityNations[$cityNation] = [];
}
$cityNations[$cityNation][] = $cityName;
}
//각 국가 전월 장수수 대비 당월 장수수로 단합도 산정
//각 국가 장수수를 구하고 국력 산정
// $query = "select nation,gennum from nation where level>0";
// 국력=
// 자원(국가/장수의 금,쌀)
// 기술력
// 인구수*내정%
// 장수능력
// 접속률
// 숙련도
// 명성,공헌
$nations = Util::convertArrayToDict($db->query('SELECT
A.nation,
A.gennum,
round((
round(((A.gold+A.rice)+(select sum(gold+rice) from general where nation=A.nation))/100)
+A.tech
+if(A.level=0,0,(
select round(
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(leadership+strength+intel) from general where nation=A.nation)
+(select round(sum(dex1+dex2+dex3+dex4+dex5)/1000) from general where nation=A.nation)
+(select round(sum(experience+dedication)/100) from general where nation=A.nation)
+(select round(avg(connect)) from general where nation=A.nation)
)/10)
as power,
(select sum(crew) from general where nation=A.nation) as totalCrew
from nation A
group by A.nation'), 'nation');
$maxPowerValues = KVStorage::getValuesFromInterNamespace($db, 'nation_env', 'max_power');
foreach ($nations as $nation) {
$nationID = $nation['nation'];
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$genNum[$nationID] = $nation['gennum'];
$powerValues = $maxPowerValues[$nationID]??[];
//약간의 랜덤치 부여 (95% ~ 105%)
$nation['power'] = Util::round($nation['power'] * (rand() % 101 + 950) / 1000);
$powerValues['maxPower'] = max($powerValues['maxPower'] ?? 0, $nation['power']);
$powerValues['maxCrew'] = max($powerValues['maxCrew'] ?? 0, Util::toInt($nation['totalCrew']));
if (count($cityNations[$nationID] ?? []) > count($powerValues['maxCities'] ?? [])) {
$powerValues['maxCities'] = $cityNations[$nationID];
}
$db->update('nation', [
'power' => $nation['power']
], 'nation=%i', $nationID);
$nationStor->max_power = $powerValues;
}
// 전쟁기한 세팅
foreach($db->query('SELECT me, you, dead, term FROM diplomacy WHERE state = 0') as $dip) {
$genCount = $genNum[$dip['me']];
// 25% 참여율일때 두당 10턴에 4000명 소모한다고 계산
// 4000 / 10 * 0.25 = 100
$term = floor($dip['dead'] / 100 / $genCount);
$dip['dead'] -= $term * 100 * $genCount;
$term = Util::valueFit($dip['term'] + $term, 0, 13);
$db->update('diplomacy', [
'term' => $term,
'dead' => $dip['dead'],
], 'me = %i AND you = %i', $dip['me'], $dip['you']);
}
//개전국 로그
foreach($db->query('SELECT me, you FROM diplomacy WHERE state = 1 AND term <= 1 AND me < you') as $dip){
$nation1 = getNationStaticInfo($dip['me']);
$name1 = $nation1['name'];
$nation2 = getNationStaticInfo($dip['you']);
$name2 = $nation2['name'];
$josaYi = JosaUtil::pick($name2, '이');
$josaWa = JosaUtil::pick($name1, '와');
$globalLogger->pushGlobalHistoryLog("<R><b>【개전】</b></><D><b>$name1</b></>{$josaWa} <D><b>$name2</b></>{$josaYi} <R>전쟁</>을 시작합니다.");
}
//휴전국 로그
$stopWarList = [];
foreach($db->queryAllLists('SELECT me,you FROM diplomacy WHERE state=0 AND term <= 1 ORDER BY me desc, you desc') as [$me, $you]){
if($me < $you){
$key = "{$me}_{$you}";
}
else{
$key = "{$you}_{$me}";
}
if(!key_exists($key, $stopWarList)){
$stopWarList[$key] = true;
continue;
}
//양측 기간 모두 0이 되는 상황이면 휴전
$nation1 = getNationStaticInfo($me);
$name1 = $nation1['name'];
$nation2 = getNationStaticInfo($you);
$name2 = $nation2['name'];
$josaWa = JosaUtil::pick($name1, '와');
$josaYi = JosaUtil::pick($name2, '이');
$globalLogger->pushGlobalHistoryLog("<R><b>【휴전】</b></><D><b>$name1</b></>{$josaWa} <D><b>$name2</b></>{$josaYi} <S>휴전</>합니다.");
$db->update('diplomacy', [
'state'=>2,
'term'=>0,
], '(me=%i AND you=%i) OR (you=%i AND me=%i)', $me, $you, $me, $you);
}
$globalLogger->flush();
//사상자 초기화, 외교 기한-1
$db->update('diplomacy', [
'dead'=>$db->sqleval('if(state!=0, 0, dead)'),
'term'=>$db->sqleval('greatest(0, term-1)'),
], true);
//불가침 끝나면 통상으로
$db->update('diplomacy', [
'state'=>2,
], 'state = 7 AND term = 0');
//선포 끝나면 교전으로
$db->update('diplomacy', [
'state'=>0,
'term'=>6,
], 'state = 1 AND term = 0');
//초반이후 방랑군 자동 해체
if ($admin['year'] >= $admin['startyear'] + 2) {
checkWander();
}
// 작위 업데이트
updateNationState();
updateGeneralNumber();
refreshNationStaticInfo();
// 천통여부 검사
checkEmperior();
//토너먼트 개시
triggerTournament();
// 시스템 거래건 등록
registerAuction();
//전방설정
foreach (getAllNationStaticInfo() as $nation) {
if ($nation['level'] <= 0) {
continue;
}
SetNationFront($nation['nation']);
}
}
function checkWander()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['year', 'month']);
$wanderers = $db->queryFirstColumn('SELECT general.`no` FROM general LEFT JOIN nation ON general.nation = nation.nation WHERE nation.`level` = 0 AND general.`officer_level` = 12');
foreach (General::createGeneralObjListFromDB($wanderers) as $wanderer) {
$wanderCmd = buildGeneralCommandClass('che_해산', $wanderer, $admin);
if ($wanderCmd->hasFullConditionMet()) {
$logger = $wanderer->getLogger();
$logger->pushGeneralActionLog('초반 제한후 방랑군은 자동 해산됩니다.', ActionLogger::PLAIN);
$wanderCmd->run();
}
}
if ($wanderers) {
refreshNationStaticInfo();
}
}
function updateNationState()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$history = array();
$admin = $gameStor->getValues(['killturn', 'year', 'month', 'fiction', 'startyear', 'show_img_level', 'turnterm', 'turntime']);
$assemblerCnts = [];
foreach ($db->queryAllLists('SELECT nation,count(no) FROM general WHERE npc = 5 GROUP BY nation') as [$nationID, $assemblerCnt]) {
$assemblerCnts[$nationID] = $assemblerCnt;
};
foreach ($db->query('SELECT nation,name,level,tech,aux FROM nation') as $nation) {
//TODO: level이 진관수이소중대특 체계를 벗어날 수 있음
$citycount = $db->queryFirstField('SELECT count(*) FROM city WHERE nation=%i AND level>=4', $nation['nation']);
if ($citycount == 0) {
$nationlevel = 0; // 방랑군
} elseif ($citycount == 1) {
$nationlevel = 1; // 호족
} elseif ($citycount <= 4) {
$nationlevel = 2; // 군벌
} elseif ($citycount <= 7) {
$nationlevel = 3; // 주자사
} elseif ($citycount <= 10) {
$nationlevel = 4; // 주목
} elseif ($citycount <= 15) {
$nationlevel = 5; // 공
} elseif ($citycount <= 20) {
$nationlevel = 6; // 왕
} else {
$nationlevel = 7; // 황제
}
if ($nationlevel > $nation['level']) {
$levelDiff = $nationlevel - $nation['level'];
$oldLevel = $nation['level'];
$nation['level'] = $nationlevel;
$updateVals = [
'level' => $nationlevel
];
switch ($nationlevel) {
case 7:
$josaUl = JosaUtil::pick(getNationLevel($nationlevel), '을');
$history[] = "<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>{$josaUl} 자칭하였습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$admin['year']}{$admin['month']}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>{$josaUl} 자칭"]);
$auxVal = Json::decode($nation['aux']);
$auxVal['can_국기변경'] = 1;
$auxVal['can_국호변경'] = 1;
$updateVals['aux'] = Json::encode($auxVal);
break;
case 6:
$history[] = "<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 등극하였습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$admin['year']}{$admin['month']}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 등극"]);
break;
case 5:
case 4:
case 3:
$history[] = "<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 임명되었습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$admin['year']}{$admin['month']}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 임명됨"]);
break;
case 2:
$history[] = "<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 독립하여 <Y>" . getNationLevel($nationlevel) . "</>로 나섰습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$admin['year']}{$admin['month']}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>로 나서다"]);
break;
}
$db->update('nation', $updateVals, 'nation=%i', $nation['nation']);
$turnRows = [];
foreach (Util::range(getNationChiefLevel($nation['level']), 12) as $chiefLevel) {
foreach (Util::range(GameConst::$maxChiefTurn) as $turnIdx) {
$turnRows[] = [
'nation_id' => $nation['nation'],
'officer_level' => $chiefLevel,
'turn_idx' => $turnIdx,
'action' => '휴식',
'arg' => null,
'brief' => '휴식'
];
}
}
$db->insertIgnore('nation_turn', $turnRows);
if ($levelDiff) {
//유니크 아이템 하나 돌리자
$targetKillTurn = $admin['killturn'];
$targetKillTurn -= 24 * 60 / $admin['turnterm'];
$nationGenIDList = $db->queryFirstColumn(
'SELECT no FROM general WHERE nation = %i AND killturn >= %i AND npc < 2',
$nation['nation'],
$targetKillTurn
);
$nationGenList = General::createGeneralObjListFromDB($nationGenIDList, ['belong'], 2);
$uniqueLotteryWeightList = [];
foreach ($nationGenList as $nationGen) {
$hasUnique = false;
foreach ($nationGen->getItems() as $item) {
if (!$item->isBuyable()) {
$hasUnique = true;
break;
}
}
if ($hasUnique) {
continue;
}
$score = $nationGen->getVar('belong') + 5;
if ($nationGen->getVar('officer_level') == 12) {
$score += 200; //NOTE: 꼬우면 군주하세요.
} else if ($nationGen->getVar('officer_level') == 11) {
$score += 70;
} else if ($nationGen->getVar('officer_level') > 4) {
$score += 35;
}
$uniqueLotteryWeightList[$nationGen->getID()] = [$nationGen, $score];
}
foreach (Util::range($levelDiff) as $idx) {
if (!$uniqueLotteryWeightList) {
break;
}
/** @var General */
$winnerObj = Util::choiceRandomUsingWeightPair($uniqueLotteryWeightList);
unset($uniqueLotteryWeightList[$winnerObj->getID()]);
giveRandomUniqueItem($winnerObj, '작위보상');
$winnerObj->applyDB($db);
}
}
}
$assemblerCnt = $assemblerCnts[$nation['nation']] ?? 0;
$maxAssemblerCnt = [
1 => 0,
2 => 1,
3 => 3,
4 => 4,
5 => 6,
6 => 7,
7 => 9
][$nationlevel] ?? 0;
if ($assemblerCnt < $maxAssemblerCnt) {
$lastAssemblerID = $gameStor->assembler_id ?? 0;
while ($assemblerCnt < $maxAssemblerCnt) {
$lastAssemblerID += 1;
$npcObj = new Scenario\NPC(
999,
sprintf('부대장%4d', $lastAssemblerID),
null,
$nation['nation'],
null,
10,
10,
10,
1,
$admin['year'] - 15,
$admin['year'] + 15,
'은둔',
'척사'
);
$npcObj->killturn = 70;
$npcObj->gold = 0;
$npcObj->rice = 0;
$npcObj->npc = 5;
$npcObj->build($admin);
$npcID = $npcObj->generalID;
$db->insert('troop', [
'troop_leader' => $npcID,
'name' => $npcObj->realName,
'nation' => $nation['nation'],
]);
$db->update('general', [
'troop' => $npcID
], 'no=%i', $npcID);
//TODO: 5턴간 집합턴 입력
$assemblerCnt += 1;
$gameStor->assembler_id = $lastAssemblerID;
}
}
}
pushGlobalHistoryLog($history, $admin['year'], $admin['month']);
}
function checkStatistic()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['year', 'month']);
$nationHists = [];
$specialHists = [];
$personalHists = [];
$specialHists2 = [];
$crewtypeHists = [];
$etc = '';
$auxData = [
'generals' => [],
'nations' => [],
];
$avgGeneral = $db->queryFirstRow(
'SELECT avg(gold) as avggold, avg(rice) as avgrice, avg(dex1+dex2+dex3+dex4) as avgdex,
max(dex1+dex2+dex3+dex4) as maxdex, avg(experience+dedication) as avgexpded, max(experience+dedication) as maxexpded
FROM general'
);
$auxData['generals']['avg'] = $avgGeneral;
$avgGeneral['avggold'] = Util::round($avgGeneral['avggold']);
$avgGeneral['avgrice'] = Util::round($avgGeneral['avgrice']);
$avgGeneral['avgdex'] = Util::round($avgGeneral['avgdex']);
$avgGeneral['avgexpded'] = Util::round($avgGeneral['avgexpded']);
$etc .= "평균 금/쌀 ({$avgGeneral['avggold']}/{$avgGeneral['avgrice']}), 평균/최고 숙련({$avgGeneral['avgdex']}/{$avgGeneral['maxdex']}), 평균/최고 경험공헌({$avgGeneral['avgexpded']}/{$avgGeneral['maxexpded']}), ";
$avgNation = $db->queryFirstRow(
'SELECT min(tech) as mintech, max(tech) as maxtech, avg(tech) as avgtech,
min(power) as minpower, max(power) as maxpower, avg(power) as avgpower from nation where level>0'
);
$auxData['nations']['avg'] = $avgNation;
$avgNation['mintech'] = floor($avgNation['mintech']);
$avgNation['maxtech'] = floor($avgNation['maxtech']);
$avgNation['avgtech'] = Util::round($avgNation['avgtech']);
$avgNation['avgpower'] = Util::round($avgNation['avgpower']);
$etc .= "최저/평균/최고 기술({$avgNation['mintech']}/{$avgNation['avgtech']}/{$avgNation['maxtech']}), ";
$etc .= "최저/평균/최고 국력({$avgNation['minpower']}/{$avgNation['avgpower']}/{$avgNation['maxpower']}), ";
$nationName = '';
$powerHist = '';
$nations = Util::convertArrayToDict(
$db->query(
'SELECT nation,name,type,power,gennum,gold+rice as goldrice from nation where level>0 order by power desc',
'nation'
),
'nation'
);
$nationCount = count($nations);
$nationGeneralInfos = Util::convertArrayToDict(
$db->query(
'SELECT nation, sum(leadership+strength+intel) as abil,sum(gold+rice) as goldrice,
sum(dex1+dex2+dex3+dex4) as dex,sum(experience+dedication) as expded
from general GROUP BY nation'
),
'nation'
);
$nationCityInfos = Util::convertArrayToDict(
$db->query('SELECT nation, count(*) as cnt, sum(pop) as pop,sum(pop_max) as pop_max from city GROUP BY nation'),
'nation'
);
foreach ($nations as $nationNo => &$nation) {
$general = $nationGeneralInfos[$nationNo];
$city = $nationCityInfos[$nationNo];
$nation['generalInfo'] = $general;
$nation['cityInfo'] = $city;
$nationName .= $nation['name'] . '(' . getNationType($nation['type']) . '), ';
$powerHist .= "{$nation['name']}({$nation['power']}/{$nation['gennum']}/{$city['cnt']}/{$city['pop']}/{$city['pop_max']}/{$nation['goldrice']}/{$general['goldrice']}/{$general['abil']}/{$general['dex']}/{$general['expded']}), ";
if (!isset($nationHists[$nation['type']])) {
$nationHists[$nation['type']] = 0;
}
$nationHists[$nation['type']]++;
}
unset($nation);
$auxData['nations']['all'] = $nations;
$nationHist = '';
foreach (GameConst::$availableNationType as $nationType) {
if (!Util::array_get($nationHists[$nationType])) {
$nationHists[$nationType] = '-';
}
$nationHist .= getNationType($nationType) . "({$nationHists[$nationType]}), ";
}
$generals = $db->query('SELECT `no`,npc,personal,special,special2,crewtype FROM general');
$genCount = 0;
$npcCount = 0;
$generalCount = count($generals);
foreach ($generals as $general) {
if (!isset($personalHists[$general['personal']])) {
$personalHists[$general['personal']] = 0;
}
if (!isset($specialHists[$general['special']])) {
$specialHists[$general['special']] = 0;
}
if (!isset($specialHists2[$general['special2']])) {
$specialHists2[$general['special2']] = 0;
}
if ($general['npc'] < 2) {
$genCount += 1;
} else {
$npcCount += 1;
}
$personalHists[$general['personal']]++;
$specialHists[$general['special']]++;
$specialHists2[$general['special2']]++;
}
foreach ($db->queryAllLists(
'SELECT crewtype, count(crewtype) AS cnt FROM general WHERE recent_war != NULL GROUP BY crewtype'
) as [$crewtype, $cnt]) {
$crewtypeHists[$crewtype] = $cnt;
}
$auxData['generals']['hists'] = [
'personal' => $personalHists,
'special' => $specialHists,
'special2' => $specialHists2,
'crewtype' => $crewtypeHists,
'userCnt' => $genCount,
'npcCnt' => $npcCount,
];
$generalCountStr = "{$generalCount}({$genCount}+{$npcCount})";
$personalHistStr = join(', ', array_map(function ($histPair) {
[$histKey, $cnt] = $histPair;
return getGenChar($histKey) . '(' . $cnt . ')';
}, Util::convertDictToArray($personalHists)));
$specialHistsStr = join(', ', array_map(function ($histPair) {
[$histKey, $cnt] = $histPair;
return getGeneralSpecialDomesticName($histKey) . '(' . $cnt . ')';
}, Util::convertDictToArray($specialHists)));
$specialHists2Str = join(', ', array_map(function ($histPair) {
[$histKey, $cnt] = $histPair;
return getGeneralSpecialWarName($histKey) . '(' . $cnt . ')';
}, Util::convertDictToArray($specialHists2)));
$specialHistsAllStr = "$specialHistsStr // $specialHists2Str";
$crewtypeHistsStr = join(', ', array_map(function ($histPair) {
[$histKey, $cnt] = $histPair;
return GameUnitConst::byID($histKey)->getShortName() . '(' . $cnt . ')';
}, Util::convertDictToArray($crewtypeHists)));
$db->insert('statistic', [
'year' => $admin['year'],
'month' => $admin['month'],
'nation_count' => $nationCount,
'nation_name' => $nationName,
'nation_hist' => $nationHist,
'gen_count' => $generalCountStr,
'personal_hist' => $personalHistStr,
'special_hist' => $specialHistsAllStr,
'power_hist' => $powerHist,
'crewtype' => $crewtypeHistsStr,
'etc' => $etc,
'aux' => Json::encode($auxData)
]);
}
function convForOldGeneral(array $general, int $year, int $month)
{
$general['history'] = getGeneralHistoryLogAll($general['no']);
return [
'server_id' => UniqueConst::$serverID,
'general_no' => $general['no'],
'owner' => $general['owner'],
'name' => $general['name'],
'last_yearmonth' => $year * 100 + $month,
'turntime' => $general['turntime'],
'data' => Json::encode($general)
];
}
function storeOldGeneral(int $no, int $year, int $month)
{
$db = DB::db();
$general = $db->queryFirstRow('SELECT * FROM general WHERE `no` = %i', $no);
if (!$general) {
return;
}
$data = convForOldGeneral($general, $year, $month);
$db->insertUpdate(
'ng_old_generals',
$data,
$data
);
}
function storeOldGenerals(int $nation, int $year, int $month)
{
$db = DB::db();
foreach ($db->query('SELECT * FROM general WHERE nation = %i', $nation) as $general) {
$data = convForOldGeneral($general, $year, $month);
$db->insertUpdate(
'ng_old_generals',
$data,
$data
);
}
}
function checkEmperior()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['year', 'month', 'isunited', 'conlimit']);
if ($admin['isunited'] != 0) {
return;
}
$remainNations = $db->queryFirstColumn('SELECT nation FROM nation WHERE level > 0 LIMIT 2');
if (!$remainNations || count($remainNations) != 1) {
return;
}
$nationID = $remainNations[0];
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$cityCnt = $db->queryFirstField('SELECT count(city) FROM city WHERE nation=%i', $nationID);
if (!$cityCnt) {
return;
}
if ($cityCnt != count(CityConst::all())) {
return;
}
checkStatistic();
$nation = $db->queryFirstRow('SELECT * FROM nation WHERE nation=%i', $nationID);
$nationName = $nation['name'];
$josaYi = JosaUtil::pick($nationName, '이');
$nationLogger = new ActionLogger(0, $nationID, $admin['year'], $admin['month']);
$nationLogger->pushNationalHistoryLog("<D><b>{$nationName}</b></>{$josaYi} 전토를 통일");
$gameStor->isunited = 2;
$gameStor->conlimit = $gameStor->conlimit * 100;
foreach ($db->queryFirstColumn('SELECT no FROM general WHERE npc<2 AND age>=%i', GameConst::$minPushHallAge) as $hallGeneralNo) {
CheckHall($hallGeneralNo);
}
[$totalPop, $totalMaxPop] = $db->queryFirstList('SELECT SUM(pop), SUM(pop_max) FROM city');
$pop = "{$totalPop} / {$totalMaxPop}";
$poprate = round($totalPop / $totalMaxPop * 100, 2). " %";
$chiefs = Util::convertArrayToDict(
$db->query(
'SELECT no,name,picture,belong,officer_level FROM general WHERE nation=%i AND officer_level >= 5',
$nationID
),
'officer_level'
);
$nationGenerals = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=%i', $nationID);
$nation['generals'] = $nationGenerals;
$tigers = $db->query(
'SELECT value, name
FROM rank_data LEFT JOIN general ON rank_data.general_id = general.no
WHERE rank_data.nation_id = %i AND rank_data.type = "warnum" AND value > 0 ORDER BY value DESC LIMIT 5',
$nationID
); // 오호장군
$tigerstr = join(', ', array_map(function ($arr) {
$number = number_format($arr['value']);
return "{$arr['name']}{$number}";
}, $tigers));
$eagles = $db->query(
'SELECT value, name
FROM rank_data LEFT JOIN general ON rank_data.general_id = general.no
WHERE rank_data.nation_id = %i AND rank_data.type = "firenum" AND value > 0 ORDER BY value DESC LIMIT 7',
$nationID
); // 건안칠자
$eaglestr = join(', ', array_map(function ($arr) {
$number = number_format($arr['value']);
return "{$arr['name']}{$number}";
}, $eagles));
$rawGeneralList = $db->query('SELECT no, name, npc, owner FROM general WHERE nation=%i ORDER BY dedication DESC', $nationID);
foreach ($rawGeneralList as $rawGeneral) {
$generalLogger = new ActionLogger($rawGeneral['no'], $nationID, $admin['year'], $admin['month']);
$generalLogger->pushGeneralActionLog("<D><b>{$nationName}</b></>{$josaYi} 전토를 통일하였습니다.", ActionLogger::YEAR_MONTH);
$generalLogger->flush();
}
$gen = join(', ', array_column($rawGeneral, 'name'));
$nation['type'] = getNationType($nation['type']);
$stat = $db->queryFirstRow('SELECT max(nation_count) as nc, max(gen_count) as gc FROM statistic');
$genCnt = $db->queryFirstField('SELECT count(*) FROM general');
$statNC = "1 / {$stat['nc']}";
$statGC = "{$genCnt} / {$stat['gc']}";
$statNation = $db->queryFirstRow('SELECT nation_count,nation_name,nation_hist from statistic where nation_count=%i LIMIT 1', $stat['nc']);
$statGeneral = $db->queryFirstRow('SELECT gen_count,personal_hist,special_hist,aux from statistic order by no desc LIMIT 1');
$nation = $nation;
$nation['generals'] = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=%i', $nation['nation']);
$nation['aux'] = Json::decode($nation['aux']);
$nation['msg'] = $nationStor->notice;
$nation['scout_msg'] = $nationStor->scout_msg;
$nation['aux'] += $nationStor->max_power;
$nation['history'] = getNationHistoryLogAll($nation['nation']);
storeOldGenerals(0, $admin['year'], $admin['month']);
storeOldGenerals($nation['nation'], $admin['year'], $admin['month']);
$db->insert('ng_old_nations', [
'server_id' => UniqueConst::$serverID,
'nation' => $nation['nation'],
'data' => Json::encode($nation)
]);
$noNationGeneral = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=0');
$db->insert('ng_old_nations', [
'server_id' => UniqueConst::$serverID,
'nation' => 0,
'data' => Json::encode([
'nation' => 0,
'name' => '재야',
'generals' => $noNationGeneral
])
]);
$nationHistory = getNationHistoryLogAll($nation['nation']);
$serverCnt = $db->queryFirstField('SELECT count(*) FROM ng_games');
$serverName = UniqueConst::$serverName;
$db->update('ng_games', [
'winner_nation' => $nation['nation']
], 'server_id=%s', UniqueConst::$serverID);
$db->insert('emperior', [
'phase' => $serverName . $serverCnt . '기',
'server_id' => UniqueConst::$serverID,
'nation_count' => $statNC,
'nation_name' => $statNation['nation_name'],
'nation_hist' => $statNation['nation_hist'],
'gen_count' => $statGC,
'personal_hist' => $statGeneral['personal_hist'],
'special_hist' => $statGeneral['special_hist'],
'name' => $nation['name'],
'type' => $nation['type'],
'color' => $nation['color'],
'year' => $admin['year'],
'month' => $admin['month'],
'power' => $nation['power'],
'gennum' => $nation['gennum'],
'citynum' => $cityCnt,
'pop' => $pop,
'poprate' => $poprate,
'gold' => $nation['gold'],
'rice' => $nation['rice'],
'l12name' => $chiefs[12]['name'],
'l12pic' => $chiefs[12]['picture'],
'l11name' => $chiefs[11]['name'],
'l11pic' => $chiefs[11]['picture'],
'l10name' => $chiefs[10]['name'],
'l10pic' => $chiefs[10]['picture'],
'l9name' => $chiefs[9]['name'],
'l9pic' => $chiefs[9]['picture'],
'l8name' => $chiefs[8]['name'],
'l8pic' => $chiefs[8]['picture'],
'l7name' => $chiefs[7]['name'],
'l7pic' => $chiefs[7]['picture'],
'l6name' => $chiefs[6]['name'],
'l6pic' => $chiefs[6]['picture'],
'l5name' => $chiefs[5]['name'],
'l5pic' => $chiefs[5]['picture'],
'tiger' => $tigerstr,
'eagle' => $eaglestr,
'gen' => $gen,
'history' => JSON::encode($nationHistory),
'aux' => $statGeneral['aux']
]);
$history = ["<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【통일】</b></><D><b>{$nation['name']}</b></>{$josaYi} 전토를 통일하였습니다."];
pushGlobalHistoryLog($history, $admin['year'], $admin['month']);
//연감 월결산
LogHistory();
}
<?php
namespace sammo;
use Monolog\Logger;
/**
* 게임 룰에 해당하는 함수 모음
*/
function getNationLevelList(): array
{
$table = [
0 => ['방랑군', 2, 0],
1 => ['호족', 2, 1],
2 => ['군벌', 4, 2],
3 => ['주자사', 4, 5],
4 => ['주목', 6, 8],
5 => ['공', 6, 11],
6 => ['왕', 8, 16],
7 => ['황제', 8, 21],
];
return $table;
}
function getCityLevelList(): array
{
return [
1 => '수',
2 => '진',
3 => '관',
4 => '이',
5 => '소',
6 => '중',
7 => '대',
8 => '특'
];
}
//한국가의 전체 전방 설정
function SetNationFront($nationNo)
{
if (!$nationNo) {
return;
}
// 도시소유 국가와 선포,교전중인 국가
$adj3 = [];
$adj2 = [];
$adj1 = [];
$db = DB::db();
foreach ($db->queryFirstColumn(
'SELECT city FROM city JOIN diplomacy ON diplomacy.you = city.nation WHERE diplomacy.state = 0 AND me = %i',
$nationNo
) as $city) {
foreach (CityConst::byID($city)->path as $adjKey => $adjVal) {
$adj3[$adjKey] = $adjVal;
}
};
foreach ($db->queryFirstColumn(
'SELECT city FROM city JOIN diplomacy ON diplomacy.you = city.nation WHERE diplomacy.state = 1 AND diplomacy.term <= 5 AND me = %i',
$nationNo
) as $city) {
foreach (CityConst::byID($city)->path as $adjKey => $adjVal) {
$adj1[$adjKey] = $adjVal;
}
}
if (!$adj3 && !$adj1) {
//평시이면 공백지
//NOTE: if, else일 경우 NPC는 전쟁시에는 공백지로 출병하지 않는다는 뜻이 된다.
foreach ($db->queryFirstColumn('SELECT city from city where nation=0') as $city) {
foreach (CityConst::byID($city)->path as $adjKey => $adjVal) {
$adj2[$adjKey] = $adjVal;
}
}
}
$db->update('city', [
'front' => 0
], 'nation=%i', $nationNo);
if ($adj1) {
$db->update('city', [
'front' => 1,
], 'nation=%i and city in %li', $nationNo, array_keys($adj1));
}
if ($adj2) {
$db->update('city', [
'front' => 2,
], 'nation=%i and city in %li', $nationNo, array_keys($adj2));
}
if ($adj3) {
$db->update('city', [
'front' => 3,
], 'nation=%i and city in %li', $nationNo, array_keys($adj3));
}
}
function checkSupply()
{
$db = DB::db();
$cities = [];
foreach ($db->query('SELECT city, nation FROM city WHERE nation != 0') as $city) {
$newCity = new \stdClass();
$newCity->id = Util::toInt($city['city']);
$newCity->nation = Util::toInt($city['nation']);
$newCity->supply = false;
$cities[$newCity->id] = $newCity;
}
$queue = new \SplQueue();
foreach ($db->queryAllLists('SELECT capital, nation FROM nation WHERE `level` > 0') as list($capitalID, $nationID)) {
if (!key_exists($capitalID, $cities)) {
continue;
}
$city = $cities[$capitalID];
if ($nationID != $city->nation) {
continue;
}
$city->supply = true;
$queue->enqueue($city);
}
while (!$queue->isEmpty()) {
$cityLink = $queue->dequeue();
$city = CityConst::byID($cityLink->id);
foreach (array_keys($city->path) as $connCityID) {
if (!key_exists($connCityID, $cities)) {
continue;
}
$connCity = $cities[$connCityID];
if ($connCity->nation != $cityLink->nation) {
continue;
}
if ($connCity->supply) {
continue;
}
$connCity->supply = true;
$queue->enqueue($connCity);
}
}
$db->update('city', [
'supply' => 1
], 'nation=0');
$db->update('city', [
'supply' => 0
], 'nation!=0');
$supply = [];
foreach ($cities as $city) {
if ($city->supply) {
$supply[] = $city->id;
}
}
if ($supply) {
$db->update('city', [
'supply' => 1
], 'city IN %li', $supply);
}
}
function updateGeneralNumber(){
$db = DB::db();
foreach($db->queryAllLists('SELECT nation, count(*) FROM general WHERE npc != 5 GROUP BY nation') as [$nationID, $gennum]){
if($nationID === 0){
continue;
}
$db->update('nation', [
'gennum'=>$gennum
], 'nation=%i', $nationID);
}
refreshNationStaticInfo();
}
function updateYearly()
{
//통계
checkStatistic();
}
//관직 변경 해제
function updateQuaterly()
{
$db = DB::db();
//천도 제한 해제, 관직 변경 제한 해제
$db->update('nation', [
'chief_set' => 0,
], true);
//관직 변경 제한 해제
$db->update('city', [
'officer_set' => 0,
], true);
}
// 벌점 감소와 건국제한-1 전턴제한-1 외교제한-1, 1달마다 실행, 병사 있는 장수의 군량 감소, 수입비율 조정
function preUpdateMonthly()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
//연감 월결산
$result = LogHistory();
if ($result == false) {
return false;
}
$admin = $gameStor->getValues(['startyear', 'year', 'month']);
$logger = new ActionLogger(0, 0, $admin['year'], $admin['month']);
//보급선 체크
checkSupply();
//미보급도시 10% 감소
$db->update('city', [
'pop' => $db->sqleval('pop * 0.9'),
'trust' => $db->sqleval('trust * 0.9'),
'agri' => $db->sqleval('agri * 0.9'),
'comm' => $db->sqleval('comm * 0.9'),
'secu' => $db->sqleval('secu * 0.9'),
'def' => $db->sqleval('def * 0.9'),
'wall' => $db->sqleval('wall * 0.9'),
], 'supply = 0');
//미보급도시 장수 병 훈 사 5%감소
//NOTE: update inner join도 가능하지만, meekrodb 기준으로 깔끔하게.
$unsuppliedCities = $db->query('SELECT city, nation, trust, name FROM city WHERE supply = 0');
foreach (Util::arrayGroupBy($unsuppliedCities, 'nation') as $nationID => $cityList) {
$cityIDList = Util::squeezeFromArray($cityList, 'city');
$db->update('general', [
'crew' => $db->sqleval('crew*0.95'),
'atmos' => $db->sqleval('atmos*0.95'),
'train' => $db->sqleval('train*0.95'),
], 'city IN %li AND nation = %i', $cityIDList, $nationID);
}
//민심30이하 공백지 처리
$lostCities = [];
foreach ($unsuppliedCities as $unsuppliedCity) {
if ($unsuppliedCity['trust'] >= 30) {
continue;
}
$lostCities[$unsuppliedCity['city']] = $unsuppliedCity;
}
if ($lostCities) {
foreach ($lostCities as $lostCity) {
$josaYi = JosaUtil::pick($lostCity['name'], '이');
$logger->pushGlobalHistoryLog("<R><b>【고립】</b></><G><b>{$lostCity['name']}</b></>{$josaYi} 보급이 끊겨 <R>미지배</> 도시가 되었습니다.");
}
$db->update('general', [
'officer_level' => 1,
'officer_city' => 0
], 'officer_city IN %li', array_keys($lostCities));
$db->update('city', [
'nation' => 0,
'officer_set' => 0,
'conflict' => '{}',
'term' => 0,
'front' => 0
], 'city IN %li', array_keys($lostCities));
}
//접률감소, 건국제한-1
$db->update('general', [
'connect' => $db->sqleval('floor(connect*0.99)'),
'makelimit' => $db->sqleval('greatest(0, makelimit - 1)'),
], true);
//전략제한-1, 외교제한-1, 세율동기화
$db->update('nation', [
'strategic_cmd_limit' => $db->sqleval('greatest(0, strategic_cmd_limit - 1)'),
'surlimit' => $db->sqleval('greatest(0, surlimit - 1)'),
'rate_tmp' => $db->sqleval('rate')
], true);
//도시훈사 180년 60, 220년 87, 240년 100
$rate = Util::round(($admin['year'] - $admin['startyear']) / 1.5) + 60;
if ($rate > 100) $rate = 100;
// 20 ~ 140원
$develcost = ($admin['year'] - $admin['startyear'] + 10) * 2;
$gameStor->city_rate = $rate;
$gameStor->develcost = $develcost;
//매달 사망자 수입 결산
processWarIncome();
//계략, 전쟁표시 해제
$db->update('city', [
'state' => $db->sqleval(<<<EOD
(CASE
WHEN state=31 THEN 0
WHEN state=32 THEN 31
WHEN state=33 THEN 0
WHEN state=34 THEN 33
WHEN state=41 THEN 0
WHEN state=42 THEN 41
WHEN state=43 THEN 42
ELSE state END)
EOD),
'term' => $db->sqleval('greatest(0, term - 1)'),
'conflict' => $db->sqleval('if(term = 0,%s,conflict)', '{}'),
], true);
//첩보-1
foreach ($db->queryAllLists("SELECT nation, spy FROM nation WHERE spy!='' AND spy!='{}'") as [$nationNo, $rawSpy]) {
$spyInfo = Json::decode($rawSpy);
foreach ($spyInfo as $cityNo => $remainMonth) {
if ($remainMonth <= 1) {
unset($spyInfo[$cityNo]);
} else {
$spyInfo[$cityNo] -= 1;
}
}
$db->update('nation', [
'spy' => Json::encode($spyInfo, Json::EMPTY_ARRAY_IS_DICT)
], 'nation=%i', $nationNo);
}
return true;
}
// 외교 로그처리, 외교 상태 처리
function postUpdateMonthly()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['startyear', 'year', 'month', 'scenario']);
$globalLogger = new ActionLogger(0, 0, $admin['year'], $admin['month']);
//도시 수 측정
$cityNations = [];
foreach ($db->queryAllLists('SELECT city, name, nation FROM city') as [$cityID, $cityName, $cityNation]) {
if (!key_exists($cityNation, $cityNations)) {
$cityNations[$cityNation] = [];
}
$cityNations[$cityNation][] = $cityName;
}
//각 국가 전월 장수수 대비 당월 장수수로 단합도 산정
//각 국가 장수수를 구하고 국력 산정
// $query = "select nation,gennum from nation where level>0";
// 국력=
// 자원(국가/장수의 금,쌀)
// 기술력
// 인구수*내정%
// 장수능력
// 접속률
// 숙련도
// 명성,공헌
$nations = Util::convertArrayToDict($db->query('SELECT
A.nation,
A.gennum,
round((
round(((A.gold+A.rice)+(select sum(gold+rice) from general where nation=A.nation))/100)
+A.tech
+if(A.level=0,0,(
select round(
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(leadership+strength+intel) from general where nation=A.nation)
+(select round(sum(dex1+dex2+dex3+dex4+dex5)/1000) from general where nation=A.nation)
+(select round(sum(experience+dedication)/100) from general where nation=A.nation)
+(select round(avg(connect)) from general where nation=A.nation)
)/10)
as power,
(select sum(crew) from general where nation=A.nation) as totalCrew
from nation A
group by A.nation'), 'nation');
$maxPowerValues = KVStorage::getValuesFromInterNamespace($db, 'nation_env', 'max_power');
foreach ($nations as $nation) {
$nationID = $nation['nation'];
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$genNum[$nationID] = $nation['gennum'];
$powerValues = $maxPowerValues[$nationID]??[];
//약간의 랜덤치 부여 (95% ~ 105%)
$nation['power'] = Util::round($nation['power'] * (rand() % 101 + 950) / 1000);
$powerValues['maxPower'] = max($powerValues['maxPower'] ?? 0, $nation['power']);
$powerValues['maxCrew'] = max($powerValues['maxCrew'] ?? 0, Util::toInt($nation['totalCrew']));
if (count($cityNations[$nationID] ?? []) > count($powerValues['maxCities'] ?? [])) {
$powerValues['maxCities'] = $cityNations[$nationID];
}
$db->update('nation', [
'power' => $nation['power']
], 'nation=%i', $nationID);
$nationStor->max_power = $powerValues;
}
// 전쟁기한 세팅
foreach($db->query('SELECT me, you, dead, term FROM diplomacy WHERE state = 0') as $dip) {
$genCount = $genNum[$dip['me']];
// 25% 참여율일때 두당 10턴에 4000명 소모한다고 계산
// 4000 / 10 * 0.25 = 100
$term = floor($dip['dead'] / 100 / $genCount);
$dip['dead'] -= $term * 100 * $genCount;
$term = Util::valueFit($dip['term'] + $term, 0, 13);
$db->update('diplomacy', [
'term' => $term,
'dead' => $dip['dead'],
], 'me = %i AND you = %i', $dip['me'], $dip['you']);
}
//개전국 로그
foreach($db->query('SELECT me, you FROM diplomacy WHERE state = 1 AND term <= 1 AND me < you') as $dip){
$nation1 = getNationStaticInfo($dip['me']);
$name1 = $nation1['name'];
$nation2 = getNationStaticInfo($dip['you']);
$name2 = $nation2['name'];
$josaYi = JosaUtil::pick($name2, '이');
$josaWa = JosaUtil::pick($name1, '와');
$globalLogger->pushGlobalHistoryLog("<R><b>【개전】</b></><D><b>$name1</b></>{$josaWa} <D><b>$name2</b></>{$josaYi} <R>전쟁</>을 시작합니다.");
}
//휴전국 로그
$stopWarList = [];
foreach($db->queryAllLists('SELECT me,you FROM diplomacy WHERE state=0 AND term <= 1 ORDER BY me desc, you desc') as [$me, $you]){
if($me < $you){
$key = "{$me}_{$you}";
}
else{
$key = "{$you}_{$me}";
}
if(!key_exists($key, $stopWarList)){
$stopWarList[$key] = true;
continue;
}
//양측 기간 모두 0이 되는 상황이면 휴전
$nation1 = getNationStaticInfo($me);
$name1 = $nation1['name'];
$nation2 = getNationStaticInfo($you);
$name2 = $nation2['name'];
$josaWa = JosaUtil::pick($name1, '와');
$josaYi = JosaUtil::pick($name2, '이');
$globalLogger->pushGlobalHistoryLog("<R><b>【휴전】</b></><D><b>$name1</b></>{$josaWa} <D><b>$name2</b></>{$josaYi} <S>휴전</>합니다.");
$db->update('diplomacy', [
'state'=>2,
'term'=>0,
], '(me=%i AND you=%i) OR (you=%i AND me=%i)', $me, $you, $me, $you);
}
$globalLogger->flush();
//사상자 초기화, 외교 기한-1
$db->update('diplomacy', [
'dead'=>$db->sqleval('if(state!=0, 0, dead)'),
'term'=>$db->sqleval('greatest(0, term-1)'),
], true);
//불가침 끝나면 통상으로
$db->update('diplomacy', [
'state'=>2,
], 'state = 7 AND term = 0');
//선포 끝나면 교전으로
$db->update('diplomacy', [
'state'=>0,
'term'=>6,
], 'state = 1 AND term = 0');
//초반이후 방랑군 자동 해체
if ($admin['year'] >= $admin['startyear'] + 2) {
checkWander();
}
// 작위 업데이트
updateNationState();
updateGeneralNumber();
refreshNationStaticInfo();
// 천통여부 검사
checkEmperior();
//토너먼트 개시
triggerTournament();
// 시스템 거래건 등록
registerAuction();
//전방설정
foreach (getAllNationStaticInfo() as $nation) {
if ($nation['level'] <= 0) {
continue;
}
SetNationFront($nation['nation']);
}
}
function checkWander()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['year', 'month']);
$wanderers = $db->queryFirstColumn('SELECT general.`no` FROM general LEFT JOIN nation ON general.nation = nation.nation WHERE nation.`level` = 0 AND general.`officer_level` = 12');
foreach (General::createGeneralObjListFromDB($wanderers) as $wanderer) {
$wanderCmd = buildGeneralCommandClass('che_해산', $wanderer, $admin);
if ($wanderCmd->hasFullConditionMet()) {
$logger = $wanderer->getLogger();
$logger->pushGeneralActionLog('초반 제한후 방랑군은 자동 해산됩니다.', ActionLogger::PLAIN);
$wanderCmd->run();
$wanderCmd->setNextAvailable();
}
}
if ($wanderers) {
refreshNationStaticInfo();
}
}
function updateNationState()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$history = array();
$admin = $gameStor->getValues(['killturn', 'year', 'month', 'fiction', 'startyear', 'show_img_level', 'turnterm', 'turntime']);
$assemblerCnts = [];
foreach ($db->queryAllLists('SELECT nation,count(no) FROM general WHERE npc = 5 GROUP BY nation') as [$nationID, $assemblerCnt]) {
$assemblerCnts[$nationID] = $assemblerCnt;
};
foreach ($db->query('SELECT nation,name,level,tech,aux FROM nation') as $nation) {
//TODO: level이 진관수이소중대특 체계를 벗어날 수 있음
$citycount = $db->queryFirstField('SELECT count(*) FROM city WHERE nation=%i AND level>=4', $nation['nation']);
if ($citycount == 0) {
$nationlevel = 0; // 방랑군
} elseif ($citycount == 1) {
$nationlevel = 1; // 호족
} elseif ($citycount <= 4) {
$nationlevel = 2; // 군벌
} elseif ($citycount <= 7) {
$nationlevel = 3; // 주자사
} elseif ($citycount <= 10) {
$nationlevel = 4; // 주목
} elseif ($citycount <= 15) {
$nationlevel = 5; // 공
} elseif ($citycount <= 20) {
$nationlevel = 6; // 왕
} else {
$nationlevel = 7; // 황제
}
if ($nationlevel > $nation['level']) {
$levelDiff = $nationlevel - $nation['level'];
$oldLevel = $nation['level'];
$nation['level'] = $nationlevel;
$updateVals = [
'level' => $nationlevel,
'gold'=>$db->sqleval('gold + %i', $nationlevel*1000),
'rice'=>$db->sqleval('rice + %i', $nationlevel*1000),
];
switch ($nationlevel) {
case 7:
$josaUl = JosaUtil::pick(getNationLevel($nationlevel), '을');
$history[] = "<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>{$josaUl} 자칭하였습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$admin['year']}{$admin['month']}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>{$josaUl} 자칭"]);
$auxVal = Json::decode($nation['aux']);
$auxVal['can_국기변경'] = 1;
$auxVal['can_국호변경'] = 1;
$updateVals['aux'] = Json::encode($auxVal);
break;
case 6:
$history[] = "<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 등극하였습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$admin['year']}{$admin['month']}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 등극"]);
break;
case 5:
case 4:
case 3:
$history[] = "<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 임명되었습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$admin['year']}{$admin['month']}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 임명됨"]);
break;
case 2:
$history[] = "<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 독립하여 <Y>" . getNationLevel($nationlevel) . "</>로 나섰습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$admin['year']}{$admin['month']}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>로 나서다"]);
break;
}
$db->update('nation', $updateVals, 'nation=%i', $nation['nation']);
$turnRows = [];
foreach (Util::range(getNationChiefLevel($nation['level']), 12) as $chiefLevel) {
foreach (Util::range(GameConst::$maxChiefTurn) as $turnIdx) {
$turnRows[] = [
'nation_id' => $nation['nation'],
'officer_level' => $chiefLevel,
'turn_idx' => $turnIdx,
'action' => '휴식',
'arg' => null,
'brief' => '휴식'
];
}
}
$db->insertIgnore('nation_turn', $turnRows);
if ($levelDiff) {
//유니크 아이템 하나 돌리자
$targetKillTurn = $admin['killturn'];
$targetKillTurn -= 24 * 60 / $admin['turnterm'];
$nationGenIDList = $db->queryFirstColumn(
'SELECT no FROM general WHERE nation = %i AND killturn >= %i AND npc < 2',
$nation['nation'],
$targetKillTurn
);
$nationGenList = General::createGeneralObjListFromDB($nationGenIDList, ['belong', 'npc'], 2);
$chiefObj = null;
$uniqueLotteryWeightList = [];
foreach ($nationGenList as $nationGen) {
if ($nationGen->getVar('officer_level') == 12) {
$chiefObj = $nationGen;
}
$trialCnt = count(GameConst::$allItems);
foreach ($nationGen->getItems() as $item) {
if (!$item->isBuyable()) {
$trialCnt -= 1;
}
}
if ($trialCnt <= 0) {
continue;
}
$score = $nationGen->getVar('belong') + 5;
if ($nationGen->getVar('officer_level') == 12) {
$score += 100; //NOTE: 꼬우면 군주하세요.
} else if ($nationGen->getVar('officer_level') == 11) {
$score += 50;
} else if ($nationGen->getVar('officer_level') > 4) {
$score += 35;
}
$score *= $trialCnt;
$uniqueLotteryWeightList[$nationGen->getID()] = [$nationGen, $score];
}
foreach (Util::range($levelDiff) as $idx) {
if (!$uniqueLotteryWeightList) {
break;
}
/** @var General */
$winnerObj = Util::choiceRandomUsingWeightPair($uniqueLotteryWeightList);
unset($uniqueLotteryWeightList[$winnerObj->getID()]);
giveRandomUniqueItem($winnerObj, '작위보상');
$winnerObj->applyDB($db);
}
if($chiefObj){
$chiefObj->increaseInheritancePoint('unifier', 250 * $levelDiff);
}
}
}
$assemblerCnt = $assemblerCnts[$nation['nation']] ?? 0;
$maxAssemblerCnt = [
1 => 0,
2 => 1,
3 => 3,
4 => 4,
5 => 6,
6 => 7,
7 => 9
][$nationlevel] ?? 0;
if ($assemblerCnt < $maxAssemblerCnt) {
$lastAssemblerID = $gameStor->assembler_id ?? 0;
while ($assemblerCnt < $maxAssemblerCnt) {
$lastAssemblerID += 1;
$npcObj = new Scenario\GeneralBuilder(
sprintf('부대장%4d', $lastAssemblerID),
0,
null,
$nation['nation']
);
$npcObj->setAffinity(999)->setStat(10, 10, 10)
->setSpecialSingle('척사')->setEgo('che_은둔')
->setKillturn(70)->setGoldRice(0, 0)
->setNPCType(5)->fillRemainSpecAsZero($admin);
$npcObj->build($admin);
$npcID = $npcObj->getGeneralID();
$db->insert('troop', [
'troop_leader' => $npcID,
'name' => $npcObj->getGeneralName(),
'nation' => $nation['nation'],
]);
$db->update('general', [
'troop' => $npcID
], 'no=%i', $npcID);
$cmd = buildGeneralCommandClass('che_집합', General::createGeneralObjFromDB($npcID), $admin);
_setGeneralCommand($cmd, iterator_to_array(Util::range(GameConst::$maxTurn)));
$assemblerCnt += 1;
$gameStor->assembler_id = $lastAssemblerID;
}
}
}
pushGlobalHistoryLog($history, $admin['year'], $admin['month']);
}
function checkStatistic()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['year', 'month']);
$nationHists = [];
$specialHists = [];
$personalHists = [];
$specialHists2 = [];
$crewtypeHists = [];
$etc = '';
$auxData = [
'generals' => [],
'nations' => [],
];
$avgGeneral = $db->queryFirstRow(
'SELECT avg(gold) as avggold, avg(rice) as avgrice, avg(dex1+dex2+dex3+dex4) as avgdex,
max(dex1+dex2+dex3+dex4) as maxdex, avg(experience+dedication) as avgexpded, max(experience+dedication) as maxexpded
FROM general'
);
$auxData['generals']['avg'] = $avgGeneral;
$avgGeneral['avggold'] = Util::round($avgGeneral['avggold']);
$avgGeneral['avgrice'] = Util::round($avgGeneral['avgrice']);
$avgGeneral['avgdex'] = Util::round($avgGeneral['avgdex']);
$avgGeneral['avgexpded'] = Util::round($avgGeneral['avgexpded']);
$etc .= "평균 금/쌀 ({$avgGeneral['avggold']}/{$avgGeneral['avgrice']}), 평균/최고 숙련({$avgGeneral['avgdex']}/{$avgGeneral['maxdex']}), 평균/최고 경험공헌({$avgGeneral['avgexpded']}/{$avgGeneral['maxexpded']}), ";
$avgNation = $db->queryFirstRow(
'SELECT min(tech) as mintech, max(tech) as maxtech, avg(tech) as avgtech,
min(power) as minpower, max(power) as maxpower, avg(power) as avgpower from nation where level>0'
);
$auxData['nations']['avg'] = $avgNation;
$avgNation['mintech'] = floor($avgNation['mintech']);
$avgNation['maxtech'] = floor($avgNation['maxtech']);
$avgNation['avgtech'] = Util::round($avgNation['avgtech']);
$avgNation['avgpower'] = Util::round($avgNation['avgpower']);
$etc .= "최저/평균/최고 기술({$avgNation['mintech']}/{$avgNation['avgtech']}/{$avgNation['maxtech']}), ";
$etc .= "최저/평균/최고 국력({$avgNation['minpower']}/{$avgNation['avgpower']}/{$avgNation['maxpower']}), ";
$nationName = '';
$powerHist = '';
$nations = Util::convertArrayToDict(
$db->query(
'SELECT nation,name,type,power,gennum,gold+rice as goldrice from nation where level>0 order by power desc',
'nation'
),
'nation'
);
$nationCount = count($nations);
$nationGeneralInfos = Util::convertArrayToDict(
$db->query(
'SELECT nation, sum(leadership+strength+intel) as abil,sum(gold+rice) as goldrice,
sum(dex1+dex2+dex3+dex4) as dex,sum(experience+dedication) as expded
from general GROUP BY nation'
),
'nation'
);
$nationCityInfos = Util::convertArrayToDict(
$db->query('SELECT nation, count(*) as cnt, sum(pop) as pop,sum(pop_max) as pop_max from city GROUP BY nation'),
'nation'
);
foreach ($nations as $nationNo => &$nation) {
$general = $nationGeneralInfos[$nationNo];
$city = $nationCityInfos[$nationNo];
$nation['generalInfo'] = $general;
$nation['cityInfo'] = $city;
$nationName .= $nation['name'] . '(' . getNationType($nation['type']) . '), ';
$powerHist .= "{$nation['name']}({$nation['power']}/{$nation['gennum']}/{$city['cnt']}/{$city['pop']}/{$city['pop_max']}/{$nation['goldrice']}/{$general['goldrice']}/{$general['abil']}/{$general['dex']}/{$general['expded']}), ";
if (!isset($nationHists[$nation['type']])) {
$nationHists[$nation['type']] = 0;
}
$nationHists[$nation['type']]++;
}
unset($nation);
$auxData['nations']['all'] = $nations;
$nationHist = '';
foreach (GameConst::$availableNationType as $nationType) {
if (!Util::array_get($nationHists[$nationType])) {
$nationHists[$nationType] = '-';
}
$nationHist .= getNationType($nationType) . "({$nationHists[$nationType]}), ";
}
$generals = $db->query('SELECT `no`,npc,personal,special,special2,crewtype FROM general');
$genCount = 0;
$npcCount = 0;
$generalCount = count($generals);
foreach ($generals as $general) {
if (!isset($personalHists[$general['personal']])) {
$personalHists[$general['personal']] = 0;
}
if (!isset($specialHists[$general['special']])) {
$specialHists[$general['special']] = 0;
}
if (!isset($specialHists2[$general['special2']])) {
$specialHists2[$general['special2']] = 0;
}
if ($general['npc'] < 2) {
$genCount += 1;
} else {
$npcCount += 1;
}
$personalHists[$general['personal']]++;
$specialHists[$general['special']]++;
$specialHists2[$general['special2']]++;
}
foreach ($db->queryAllLists(
'SELECT crewtype, count(crewtype) AS cnt FROM general WHERE recent_war != NULL GROUP BY crewtype'
) as [$crewtype, $cnt]) {
$crewtypeHists[$crewtype] = $cnt;
}
$auxData['generals']['hists'] = [
'personal' => $personalHists,
'special' => $specialHists,
'special2' => $specialHists2,
'crewtype' => $crewtypeHists,
'userCnt' => $genCount,
'npcCnt' => $npcCount,
];
$generalCountStr = "{$generalCount}({$genCount}+{$npcCount})";
$personalHistStr = join(', ', array_map(function ($histPair) {
[$histKey, $cnt] = $histPair;
return getGenChar($histKey) . '(' . $cnt . ')';
}, Util::convertDictToArray($personalHists)));
$specialHistsStr = join(', ', array_map(function ($histPair) {
[$histKey, $cnt] = $histPair;
return getGeneralSpecialDomesticName($histKey) . '(' . $cnt . ')';
}, Util::convertDictToArray($specialHists)));
$specialHists2Str = join(', ', array_map(function ($histPair) {
[$histKey, $cnt] = $histPair;
return getGeneralSpecialWarName($histKey) . '(' . $cnt . ')';
}, Util::convertDictToArray($specialHists2)));
$specialHistsAllStr = "$specialHistsStr // $specialHists2Str";
$crewtypeHistsStr = join(', ', array_map(function ($histPair) {
[$histKey, $cnt] = $histPair;
return GameUnitConst::byID($histKey)->getShortName() . '(' . $cnt . ')';
}, Util::convertDictToArray($crewtypeHists)));
$db->insert('statistic', [
'year' => $admin['year'],
'month' => $admin['month'],
'nation_count' => $nationCount,
'nation_name' => $nationName,
'nation_hist' => $nationHist,
'gen_count' => $generalCountStr,
'personal_hist' => $personalHistStr,
'special_hist' => $specialHistsAllStr,
'power_hist' => $powerHist,
'crewtype' => $crewtypeHistsStr,
'etc' => $etc,
'aux' => Json::encode($auxData)
]);
}
function convForOldGeneral(array $general, int $year, int $month)
{
$general['history'] = getGeneralHistoryLogAll($general['no']);
return [
'server_id' => UniqueConst::$serverID,
'general_no' => $general['no'],
'owner' => $general['owner'],
'name' => $general['name'],
'last_yearmonth' => $year * 100 + $month,
'turntime' => $general['turntime'],
'data' => Json::encode($general)
];
}
function storeOldGeneral(int $no, int $year, int $month)
{
$db = DB::db();
$general = $db->queryFirstRow('SELECT * FROM general WHERE `no` = %i', $no);
if (!$general) {
return;
}
$data = convForOldGeneral($general, $year, $month);
$db->insertUpdate(
'ng_old_generals',
$data,
$data
);
}
function storeOldGenerals(int $nation, int $year, int $month)
{
$db = DB::db();
foreach ($db->query('SELECT * FROM general WHERE nation = %i', $nation) as $general) {
$data = convForOldGeneral($general, $year, $month);
$db->insertUpdate(
'ng_old_generals',
$data,
$data
);
}
}
function checkEmperior()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['year', 'month', 'isunited', 'conlimit']);
if ($admin['isunited'] != 0) {
return;
}
$remainNations = $db->queryFirstColumn('SELECT nation FROM nation WHERE level > 0 LIMIT 2');
if (!$remainNations || count($remainNations) != 1) {
return;
}
$nationID = $remainNations[0];
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$cityCnt = $db->queryFirstField('SELECT count(city) FROM city WHERE nation=%i', $nationID);
if (!$cityCnt) {
return;
}
if ($cityCnt != count(CityConst::all())) {
return;
}
checkStatistic();
$nation = $db->queryFirstRow('SELECT * FROM nation WHERE nation=%i', $nationID);
$nationName = $nation['name'];
$josaYi = JosaUtil::pick($nationName, '이');
$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 = 0')) as $genObj){
if($genObj->getNationID() == $nationID){
if($genObj->getVar('officer_level') > 4){
$genObj->increaseInheritancePoint('unifier', 2000);
};
}
$genObj->mergeTotalInheritancePoint();
}
$gameStor->isunited = 2;
$gameStor->conlimit = $gameStor->conlimit * 100;
foreach ($db->queryFirstColumn('SELECT no FROM general WHERE npc<2 AND age>=%i', GameConst::$minPushHallAge) as $hallGeneralNo) {
CheckHall($hallGeneralNo);
}
[$totalPop, $totalMaxPop] = $db->queryFirstList('SELECT SUM(pop), SUM(pop_max) FROM city');
$pop = "{$totalPop} / {$totalMaxPop}";
$poprate = round($totalPop / $totalMaxPop * 100, 2). " %";
$chiefs = Util::convertArrayToDict(
$db->query(
'SELECT no,name,picture,belong,officer_level FROM general WHERE nation=%i AND officer_level >= 5',
$nationID
),
'officer_level'
);
$nationGenerals = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=%i', $nationID);
$nation['generals'] = $nationGenerals;
$tigers = $db->query(
'SELECT value, name
FROM rank_data LEFT JOIN general ON rank_data.general_id = general.no
WHERE rank_data.nation_id = %i AND rank_data.type = "killnum" AND value > 0 ORDER BY value DESC LIMIT 5',
$nationID
); // 오호장군
$tigerstr = join(', ', array_map(function ($arr) {
$number = number_format($arr['value']);
return "{$arr['name']}{$number}";
}, $tigers));
$eagles = $db->query(
'SELECT value, name
FROM rank_data LEFT JOIN general ON rank_data.general_id = general.no
WHERE rank_data.nation_id = %i AND rank_data.type = "firenum" AND value > 0 ORDER BY value DESC LIMIT 7',
$nationID
); // 건안칠자
$eaglestr = join(', ', array_map(function ($arr) {
$number = number_format($arr['value']);
return "{$arr['name']}{$number}";
}, $eagles));
$rawGeneralList = $db->query('SELECT no, name, npc, owner FROM general WHERE nation=%i ORDER BY dedication DESC', $nationID);
foreach ($rawGeneralList as $rawGeneral) {
$generalLogger = new ActionLogger($rawGeneral['no'], $nationID, $admin['year'], $admin['month']);
$generalLogger->pushGeneralActionLog("<D><b>{$nationName}</b></>{$josaYi} 전토를 통일하였습니다.", ActionLogger::YEAR_MONTH);
$generalLogger->flush();
}
$gen = join(', ', array_column($rawGeneral, 'name'));
$stat = $db->queryFirstRow('SELECT max(nation_count) as nc, max(gen_count) as gc FROM statistic');
$genCnt = $db->queryFirstField('SELECT count(*) FROM general');
$statNC = "1 / {$stat['nc']}";
$statGC = "{$genCnt} / {$stat['gc']}";
$statNation = $db->queryFirstRow('SELECT nation_count,nation_name,nation_hist from statistic where nation_count=%i LIMIT 1', $stat['nc']);
$statGeneral = $db->queryFirstRow('SELECT gen_count,personal_hist,special_hist,aux from statistic order by no desc LIMIT 1');
$nation = $nation;
$nation['generals'] = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=%i', $nation['nation']);
$nation['aux'] = Json::decode($nation['aux']);
$nation['msg'] = $nationStor->notice;
$nation['scout_msg'] = $nationStor->scout_msg;
$nation['aux'] += $nationStor->max_power;
$nation['history'] = getNationHistoryLogAll($nation['nation']);
storeOldGenerals(0, $admin['year'], $admin['month']);
storeOldGenerals($nation['nation'], $admin['year'], $admin['month']);
$db->insert('ng_old_nations', [
'server_id' => UniqueConst::$serverID,
'nation' => $nation['nation'],
'data' => Json::encode($nation)
]);
$noNationGeneral = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=0');
$db->insert('ng_old_nations', [
'server_id' => UniqueConst::$serverID,
'nation' => 0,
'data' => Json::encode([
'nation' => 0,
'name' => '재야',
'generals' => $noNationGeneral
])
]);
$nationHistory = getNationHistoryLogAll($nation['nation']);
$serverCnt = $db->queryFirstField('SELECT count(*) FROM ng_games');
$serverName = UniqueConst::$serverName;
$db->update('ng_games', [
'winner_nation' => $nation['nation']
], 'server_id=%s', UniqueConst::$serverID);
$db->insert('emperior', [
'phase' => $serverName . $serverCnt . '기',
'server_id' => UniqueConst::$serverID,
'nation_count' => $statNC,
'nation_name' => $statNation['nation_name'],
'nation_hist' => $statNation['nation_hist'],
'gen_count' => $statGC,
'personal_hist' => $statGeneral['personal_hist'],
'special_hist' => $statGeneral['special_hist'],
'name' => $nation['name'],
'type' => $nation['type'],
'color' => $nation['color'],
'year' => $admin['year'],
'month' => $admin['month'],
'power' => $nation['power'],
'gennum' => $nation['gennum'],
'citynum' => $cityCnt,
'pop' => $pop,
'poprate' => $poprate,
'gold' => $nation['gold'],
'rice' => $nation['rice'],
'l12name' => $chiefs[12]['name'],
'l12pic' => $chiefs[12]['picture'],
'l11name' => $chiefs[11]['name'],
'l11pic' => $chiefs[11]['picture'],
'l10name' => $chiefs[10]['name'],
'l10pic' => $chiefs[10]['picture'],
'l9name' => $chiefs[9]['name'],
'l9pic' => $chiefs[9]['picture'],
'l8name' => $chiefs[8]['name'],
'l8pic' => $chiefs[8]['picture'],
'l7name' => $chiefs[7]['name'],
'l7pic' => $chiefs[7]['picture'],
'l6name' => $chiefs[6]['name'],
'l6pic' => $chiefs[6]['picture'],
'l5name' => $chiefs[5]['name'],
'l5pic' => $chiefs[5]['picture'],
'tiger' => $tigerstr,
'eagle' => $eaglestr,
'gen' => $gen,
'history' => JSON::encode($nationHistory),
'aux' => $statGeneral['aux']
]);
$history = ["<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【통일】</b></><D><b>{$nation['name']}</b></>{$josaYi} 전토를 통일하였습니다."];
pushGlobalHistoryLog($history, $admin['year'], $admin['month']);
//연감 월결산
LogHistory();
}
function resetInheritanceUser(int $userID){
$inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$userID}");
$totalPoint = 0;
foreach($inheritStor->getAll() as [$value,]){
$totalPoint += $value;
}
$totalPoint = Util::toInt($totalPoint);
$inheritStor->resetValues();
$inheritStor->setValue('previous', [$totalPoint, null]);
}
function updateMaxDomesticCritical(General $general, $score){
$maxDomesticCritical = $general->getAuxVar('max_domestic_critical')??0;
$maxDomesticCritical += $score / 2;
$general->setAuxVar('max_domestic_critical', $maxDomesticCritical);
$oldMaxDomesticCritical = $general->getInheritancePoint('max_domestic_critical');
if($maxDomesticCritical > $oldMaxDomesticCritical){
$general->setInheritancePoint('max_domestic_critical', $maxDomesticCritical);
}
}
+20 -4
View File
@@ -39,10 +39,26 @@ function bar($per, $h=7) {
}
function optionsForCities() {
return join('', array_map(function($city){
return "<option value='{$city->id}'>{$city->name}</option>";
}, CityConst::all()));
function optionsForCities(callable $infoCall=null) {
if(!$infoCall){
return join('', array_map(function($city){
return "<option value='{$city->id}'>{$city->name}</option>";
}, CityConst::all()));
}
$infoList = [];
$noInfoList = [];
foreach(CityConst::all() as $city){
$info = $infoCall($city);
if(!$info){
$noInfoList[] = "<option value='{$city->id}'>{$city->name}</option>";
continue;
}
$infoList[] = "<option value='{$city->id}'>{$city->name} ({$info})</option>";
}
return join('', array_merge($infoList, $noInfoList));
}
function Submit($url, $msg="", $msg2="") {
+274 -270
View File
@@ -1,270 +1,274 @@
<?php
namespace sammo;
/**
* 템플릿 생성과 관련된 함수들을 모아두는 파일
*
* NOTE: 아직 converter와 명확한 구분이 되어있지 않음.
* TODO: legacy template들을 전부 template 폴더로 모아둘 필요 있음
* TODO: side effect를 제거
*/
/**
* 관리자 권한이 필요함을 출력.
* @return void
*/
function requireAdminPermissionHTML()
{
ob_start();
?>
<!DOCTYPE html>
<html>
<head>
<title>관리메뉴</title>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<?= WebUtil::printCSS('css/common.css') ?>
</head>
<body>
관리자가 아닙니다.<br>
<?= banner() ?>
</body>
</html>
<?php
return ob_get_clean();
}
function turnTable()
{
$turnList = [];
$turnList[] = "<option selected value='0'>1턴</option>";
foreach (Util::range(1, GameConst::$maxTurn) as $turnIdx) {
$turnText = $turnIdx + 1;
$turnList[] = "<option value='{$turnIdx}'>{$turnText}턴</option>";
}
$turnText = join("\n", $turnList);
return "
<select id='generalTurnSelector' name=turn[] size=11 multiple>
<option value='-3'>전체</option>
<option value='-1'>홀턴</option>
<option value='-2'>짝턴</option>
{$turnText}
</select>
";
}
function chiefTurnTable()
{
$turnList = [];
$turnList[] = "<option selected value='0'>1턴</option>";
foreach (Util::range(1, GameConst::$maxChiefTurn) as $turnIdx) {
$turnText = $turnIdx + 1;
$turnList[] = "<option value='{$turnIdx}'>{$turnText}턴</option>";
}
$turnText = join("\n", $turnList);
return "
<select id='chiefTurnSelector' name=turn[] size=6 multiple>
{$turnText}
</select>
";
}
function displayiActionObjInfo(?iAction $action)
{
if ($action === null) {
$info = '';
$text = '-';
} else {
$info = $action->getInfo();
$text = $action->getName();
}
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
return $templates->render('tooltip', [
'text' => $text,
'info' => $info,
]);
}
function displayCharInfo(string $type): string
{
$class = buildPersonalityClass($type);
$info = $class->getInfo();
$text = $class->getName();
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
return $templates->render('tooltip', [
'text' => $text,
'info' => $info,
]);
}
function displaySpecialWarInfo(?string $type): string
{
$class = buildGeneralSpecialWarClass($type);
$info = $class->getInfo();
$name = $class->getName();
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
return $templates->render('tooltip', [
'text' => $name,
'info' => $info,
]);
}
function displaySpecialDomesticInfo(?string $type): string
{
$class = buildGeneralSpecialDomesticClass($type);
$info = $class->getInfo();
$name = $class->getName();
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
return $templates->render('tooltip', [
'text' => $name,
'info' => $info,
]);
}
function allButton(bool $seizeNPCMode)
{
if ($seizeNPCMode) {
$site = "a_npcList.php";
$call = "빙의일람";
} else {
$site = "a_vote.php";
$call = "설문조사";
}
if (\file_exists(__DIR__ . "/d_setting/templates/allButton.php")) {
$templates = new \League\Plates\Engine(__DIR__ . '/d_setting/templates');
} else {
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
}
return $templates->render('allButton', [
'call' => $call,
'site' => $site
]);
}
function commandButton()
{
$session = Session::getInstance();
$userID = Session::getUserID();
if (!$session->isGameLoggedIn()) {
return '';
}
$db = DB::db();
$me = $db->queryFirstRow("select no,nation,officer_level,belong,permission,penalty from general where owner=%i", $userID);
$nation = $db->queryFirstRow("select nation,level,color,secretlimit from nation where nation=%i", $me['nation']) ?? [
'nation' => 0,
'level' => 0,
'secretlimit' => 99,
'color' => '#000000'
];
$bgColor = Util::array_get($nation['color']) ?: '#000000';
$fgColor = newColor($bgColor);
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
$showSecret = false;
$permission = checkSecretPermission($me);
if ($permission >= 1) {
$showSecret = true;
} else if ($me['officer_level'] == 0) {
$showSecret = false;
}
return $templates->render('commandButton', [
'bgColor' => $bgColor,
'fgColor' => $fgColor,
'meLevel' => $me['officer_level'],
'nationLevel' => $nation['level'],
'showSecret' => $showSecret,
'permission' => $permission,
]);
}
function formatWounded(int $value, int $wound): string
{
if ($wound == 0) {
return "$value";
}
$woundedValue = intdiv($value * (100 - $wound), 100);
return "<font color=red>$woundedValue</font>";
}
function formatDefenceTrain(int $value): string
{
if ($value === 999) {
return "×";
} else if ($value >= 80) {
return "";
} else {
return "";
}
}
function formatLeadershipBonus(int $value): string
{
if ($value == 0) {
return '';
}
return "<font color=cyan>+{$value}</font>";
}
function formatName(string $name, int $npc): string
{
if ($npc == 1) {
$name = "<font color='skyblue'>$name</font>";
} else if ($npc > 1) {
$name = "<font color='cyan'>$name</font>";
}
return $name;
}
function getMapHtml(?string $mapTheme = 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';
}
return $templates->render('map', [
'mapTheme' => $mapTheme
]);
}
function getInvitationList(array $nationList)
{
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
foreach ($nationList as &$nation) {
$nation['textColor'] = newColor($nation['color']);
}
return $templates->render('invitationList', [
'nationList' => $nationList
]);
}
<?php
namespace sammo;
/**
* 템플릿 생성과 관련된 함수들을 모아두는 파일
*
* NOTE: 아직 converter와 명확한 구분이 되어있지 않음.
* TODO: legacy template들을 전부 template 폴더로 모아둘 필요 있음
* TODO: side effect를 제거
*/
/**
* 관리자 권한이 필요함을 출력.
* @return void
*/
function requireAdminPermissionHTML()
{
ob_start();
?>
<!DOCTYPE html>
<html>
<head>
<title>관리메뉴</title>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<?= WebUtil::printCSS('css/common.css') ?>
</head>
<body>
관리자가 아닙니다.<br>
<?= banner() ?>
</body>
</html>
<?php
return ob_get_clean();
}
function turnTable()
{
$turnList = [];
$turnList[] = "<option selected value='0'>1턴</option>";
foreach (Util::range(1, GameConst::$maxTurn) as $turnIdx) {
$turnText = $turnIdx + 1;
$turnList[] = "<option value='{$turnIdx}'>{$turnText}턴</option>";
}
$turnText = join("\n", $turnList);
return "
<select id='generalTurnSelector' name=turn[] size=11 multiple>
<option value='-3'>전체</option>
<option value='-1'>홀턴</option>
<option value='-2'>짝턴</option>
{$turnText}
</select>
";
}
function chiefTurnTable()
{
$turnList = [];
$turnList[] = "<option selected value='0'>1턴</option>";
foreach (Util::range(1, GameConst::$maxChiefTurn) as $turnIdx) {
$turnText = $turnIdx + 1;
$turnList[] = "<option value='{$turnIdx}'>{$turnText}턴</option>";
}
$turnText = join("\n", $turnList);
return "
<select id='chiefTurnSelector' name=turn[] size=6 multiple>
{$turnText}
</select>
";
}
function displayiActionObjInfo(?iAction $action)
{
if ($action === null) {
$info = '';
$text = '-';
} else {
$info = $action->getInfo();
$text = $action->getName();
}
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
return $templates->render('tooltip', [
'text' => $text,
'info' => $info,
]);
}
function displayCharInfo(string $type): string
{
$class = buildPersonalityClass($type);
$info = $class->getInfo();
$text = $class->getName();
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
return $templates->render('tooltip', [
'text' => $text,
'info' => $info,
]);
}
function displaySpecialWarInfo(?string $type): string
{
$class = buildGeneralSpecialWarClass($type);
$info = $class->getInfo();
$name = $class->getName();
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
return $templates->render('tooltip', [
'text' => $name,
'info' => $info,
]);
}
function displaySpecialDomesticInfo(?string $type): string
{
$class = buildGeneralSpecialDomesticClass($type);
$info = $class->getInfo();
$name = $class->getName();
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
return $templates->render('tooltip', [
'text' => $name,
'info' => $info,
]);
}
function allButton(bool $seizeNPCMode)
{
if ($seizeNPCMode) {
$site = "a_npcList.php";
$call = "빙의일람";
} else {
$site = "a_vote.php";
$call = "설문조사";
}
if (\file_exists(__DIR__ . "/d_setting/templates/allButton.php")) {
$templates = new \League\Plates\Engine(__DIR__ . '/d_setting/templates');
} else {
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
}
return $templates->render('allButton', [
'call' => $call,
'site' => $site
]);
}
function commandButton()
{
$session = Session::getInstance();
$userID = Session::getUserID();
if (!$session->isGameLoggedIn()) {
return '';
}
$db = DB::db();
$me = $db->queryFirstRow("select no,nation,officer_level,belong,permission,penalty from general where owner=%i", $userID);
$nation = $db->queryFirstRow("select nation,level,color,secretlimit from nation where nation=%i", $me['nation']) ?? [
'nation' => 0,
'level' => 0,
'secretlimit' => 99,
'color' => '#000000'
];
$bgColor = Util::array_get($nation['color']) ?: '#000000';
$fgColor = newColor($bgColor);
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
$showSecret = false;
$permission = checkSecretPermission($me);
if ($permission >= 1) {
$showSecret = true;
} else if ($me['officer_level'] == 0) {
$showSecret = false;
}
return $templates->render('commandButton', [
'bgColor' => $bgColor,
'fgColor' => $fgColor,
'meLevel' => $me['officer_level'],
'nationLevel' => $nation['level'],
'showSecret' => $showSecret,
'permission' => $permission,
]);
}
function formatWounded(int $value, int $wound): string
{
if ($wound == 0) {
return "$value";
}
$woundedValue = intdiv($value * (100 - $wound), 100);
return "<font color=red>$woundedValue</font>";
}
function formatDefenceTrain(int $value): string
{
if ($value === 999) {
return "×";
} else if ($value >= 90){
return "";
} else if ($value >= 80) {
return "";
} else if ($value >= 60) {
return "";
} else{
return "";
}
}
function formatLeadershipBonus(int $value): string
{
if ($value == 0) {
return '';
}
return "<font color=cyan>+{$value}</font>";
}
function formatName(string $name, int $npc): string
{
if ($npc == 1) {
$name = "<font color='skyblue'>$name</font>";
} else if ($npc > 1) {
$name = "<font color='cyan'>$name</font>";
}
return $name;
}
function getMapHtml(?string $mapTheme = 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';
}
return $templates->render('map', [
'mapTheme' => $mapTheme
]);
}
function getInvitationList(array $nationList)
{
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
foreach ($nationList as &$nation) {
$nation['textColor'] = newColor($nation['color']);
}
return $templates->render('invitationList', [
'nationList' => $nationList
]);
}
+23 -17
View File
@@ -78,6 +78,7 @@ function processGoldIncome() {
// 실지급률
$ratio = $realoutcome / $originoutcome;
}
$nation['gold'] = Util::valueFit($nation['gold'], GameConst::$basegold);
$adminLog[] = StringUtil::padStringAlignRight((string)$nation['name'],12," ")
." // 세금 : ".StringUtil::padStringAlignRight((string)$income,6," ")
." // 세출 : ".StringUtil::padStringAlignRight((string)$originoutcome,6," ")
@@ -87,6 +88,8 @@ function processGoldIncome() {
$incomeText = number_format($income);
$incomeLog = "이번 수입은 금 <C>$incomeText</>입니다.";
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$nationStor->prev_income_gold = $income;
$db->update('nation', [
'gold'=>$nation['gold']
@@ -353,6 +356,7 @@ function processRiceIncome() {
// 실지급률
$ratio = $realoutcome / $originoutcome;
}
$nation['rice'] = Util::valueFit($nation['rice'], GameConst::$baserice);
$adminLog[] = StringUtil::padStringAlignRight($nation['name'],12," ")
." // 세곡 : ".StringUtil::padStringAlignRight((string)$income,6," ")
." // 세출 : ".StringUtil::padStringAlignRight((string)$originoutcome,6," ")
@@ -362,6 +366,8 @@ function processRiceIncome() {
$incomeText = number_format($income);
$incomeLog = "이번 수입은 쌀 <C>$incomeText</>입니다.";
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$nationStor->prev_income_rice = $income;
$db->update('nation', [
'rice'=>$nation['rice']
@@ -528,36 +534,36 @@ function disaster() {
$targetCityNames = "<G><b>".join(' ', Util::squeezeFromArray($targetCityList, 'name'))."</b></>";
$disasterTextList = [
1 => [
['재난', 4, '역병이 발생하여 도시가 황폐해지고 있습니다.'],
['재난', 5, '지진으로 피해가 속출하고 있습니다.'],
['재난', 3, '추위가 풀리지 않아 얼어죽는 백성들이 늘어나고 있습니다.'],
['재난', 9, '황건적이 출현해 도시를 습격하고 있습니다.'],
['<M><b>【재난】</b></>', 4, '역병이 발생하여 도시가 황폐해지고 있습니다.'],
['<M><b>【재난】</b></>', 5, '지진으로 피해가 속출하고 있습니다.'],
['<M><b>【재난】</b></>', 3, '추위가 풀리지 않아 얼어죽는 백성들이 늘어나고 있습니다.'],
['<M><b>【재난】</b></>', 9, '황건적이 출현해 도시를 습격하고 있습니다.'],
],
4 => [
['재난', 7, '홍수로 인해 피해가 급증하고 있습니다.'],
['재난', 5, '지진으로 피해가 속출하고 있습니다.'],
['재난', 6, '태풍으로 인해 피해가 속출하고 있습니다.'],
['<M><b>【재난】</b></>', 7, '홍수로 인해 피해가 급증하고 있습니다.'],
['<M><b>【재난】</b></>', 5, '지진으로 피해가 속출하고 있습니다.'],
['<M><b>【재난】</b></>', 6, '태풍으로 인해 피해가 속출하고 있습니다.'],
],
7 => [
['재난', 8, '메뚜기 떼가 발생하여 도시가 황폐해지고 있습니다.'],
['재난', 5, '지진으로 피해가 속출하고 있습니다.'],
['재난', 8, '흉년이 들어 굶어죽는 백성들이 늘어나고 있습니다.'],
['<M><b>【재난】</b></>', 8, '메뚜기 떼가 발생하여 도시가 황폐해지고 있습니다.'],
['<M><b>【재난】</b></>', 5, '지진으로 피해가 속출하고 있습니다.'],
['<M><b>【재난】</b></>', 8, '흉년이 들어 굶어죽는 백성들이 늘어나고 있습니다.'],
],
10 => [
['재난', 3, '혹한으로 도시가 황폐해지고 있습니다.'],
['재난', 5, '지진으로 피해가 속출하고 있습니다.'],
['재난', 3, '눈이 많이 쌓여 도시가 황폐해지고 있습니다.'],
['재난', 9, '황건적이 출현해 도시를 습격하고 있습니다.'],
['<M><b>【재난】</b></>', 3, '혹한으로 도시가 황폐해지고 있습니다.'],
['<M><b>【재난】</b></>', 5, '지진으로 피해가 속출하고 있습니다.'],
['<M><b>【재난】</b></>', 3, '눈이 많이 쌓여 도시가 황폐해지고 있습니다.'],
['<M><b>【재난】</b></>', 9, '황건적이 출현해 도시를 습격하고 있습니다.'],
]
];
$boomingTextList = [
1 => null,
4 => [
['호황', 2, '호황으로 도시가 번창하고 있습니다.'],
['<C><b>【호황】</b></>', 2, '호황으로 도시가 번창하고 있습니다.'],
],
7 => [
['풍작', 1, '풍작으로 도시가 번창하고 있습니다.'],
['<C><b>【풍작】</b></>', 1, '풍작으로 도시가 번창하고 있습니다.'],
],
10 => null
];
@@ -566,7 +572,7 @@ function disaster() {
$logger = new ActionLogger(0, 0, $year, $month, false);
$logger->pushGlobalHistoryLog("<M><b>【{$logTitle}】</b></>{$targetCityNames}{$logBody}");
$logger->pushGlobalHistoryLog("{$logTitle}{$targetCityNames}{$logBody}");
$logger->flush();
if (!$isGood) {
+12 -7
View File
@@ -523,7 +523,7 @@ function selection($tnmt_type, $tnmt, $phase) {
if($phase < 31) {
$gameStor->phase+=1;
} else {
$gameStor->tournamemt = 4;
$gameStor->tournament = 4;
$gameStor->phase=0;
}
}
@@ -689,7 +689,8 @@ function setGift($tnmt_type, $tnmt, $phase) {
'grp_no'=>$general['grp_no'],
'reward'=>$cost,
'msg'=>"<span class='ev_highlight'>16강 진출</span>",
'logger'=>$logger
'logger'=>$logger,
'inheritance_point'=>10,
];
}
//8강자 명성 돈
@@ -723,6 +724,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);
}
//결승자 명성 돈
$cost = $admin['develcost'] * 6;
@@ -739,6 +741,7 @@ function setGift($tnmt_type, $tnmt, $phase) {
//포상 장수 이름, 금액
$resultHelper[$generalID]['reward'] += $cost;
$resultHelper[$generalID]['msg'] = "<span class='ev_highlight'>준우승</span>으";
$resultHelper[$generalID]['inheritance_point'] = 50;
if($general['lose'] > 0){
$runnerUp = $general;
}
@@ -761,6 +764,7 @@ function setGift($tnmt_type, $tnmt, $phase) {
//포상 장수 이름, 금액
$resultHelper[$generalID]['reward'] += $cost;
$resultHelper[$generalID]['msg'] = "<span class='ev_highlight'>우승</span>으";
$resultHelper[$generalID]['inheritance_point'] = 100;
$winner = $general;
}
@@ -775,9 +779,6 @@ function setGift($tnmt_type, $tnmt, $phase) {
$runnerUpLogger = $resultHelper[$runnerUp['no']]['logger'];
$runnerUpLogger->pushGeneralHistoryLog("<C>{$tp}</> 대회에서 준우승");
$winnerRewardText = number_format($resultHelper[$winner['no']]['reward']);
$runnerUpRewardText = number_format($resultHelper[$runnerUp['no']]['reward']);
@@ -786,12 +787,16 @@ function setGift($tnmt_type, $tnmt, $phase) {
$winnerLogger->pushGlobalHistoryLog("<C>{$tp}</> 대회에서 <Y>{$winner['name']}</>{$josaYiWinner} <C>우승</>, <Y>{$runnerUp['name']}</>{$josaYiRunnerUp} <C>준우승</>을 차지하여 천하에 이름을 떨칩니다!", ActionLogger::EVENT_YEAR_MONTH);
$winnerLogger->pushGlobalHistoryLog("<C>{$tp}</> 대회의 <S>우승자</>에게는 <C>{$winnerRewardText}</>, <S>준우승자</>에겐 <C>{$runnerUpRewardText}</>의 <S>상금</>과 약간의 <S>명성</>이 주어집니다!", ActionLogger::EVENT_YEAR_MONTH);
foreach($resultHelper as $general){
$generalObjList = General::createGeneralObjListFromDB(array_keys($resultHelper));
foreach($resultHelper as $generalID=>$general){
$rewardText = number_format($general['reward']);
/** @var ActionLogger */
$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']);
}
//우승자 번호
+7 -5
View File
@@ -61,7 +61,7 @@ $scenario = $gameStor->scenario_text;
$nationID = $generalObj->getNationID();
if($nationID){
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$nationStor->cacheValues(['notice', 'online_genenerals']);
$nationStor->cacheAll();
}
$valid = 0;
@@ -79,9 +79,11 @@ if ($gameStor->fiction == 0) {
}
if ($gameStor->npcmode == 0) {
$npcmode = "불가능";
} else {
} else if($gameStor->npcmode == 1){
$npcmode = "가능";
$valid = 1;
} else {
$npcmode = "선택 생성";
}
$color = "cyan";
$mapTheme = $gameStor->map_theme;
@@ -134,7 +136,7 @@ $(function(){
<body class="img_back">
<div id="container">
<div><?=allButton($gameStor->npcmode!=0)?></div>
<div><?=allButton($gameStor->npcmode==1)?></div>
<table class="tb_layout bg0" style="width:1000px;">
<tr height=50>
<td colspan=5 id="server_title" align=center><font size=4>삼국지 모의전투 HiDCHe <?=$serverName.$serverCnt?>기 (<font color=cyan><?=$scenario?></font>)</font></td>
@@ -341,7 +343,7 @@ else if($session->userGrade == 4){
<button id="msg_submit">서신전달&amp;갱신</button><br>
내용 없이 '서신전달&amp;갱신' 누르면 메세지창이 갱신됩니다.
</div>
<div><?=allButton($gameStor->npcmode!=0)?></div>
<div><?=allButton($gameStor->npcmode==1)?></div>
<div id="message_board"><div style="left:0;" class="board_side bg0">
<div class="board_header bg0" id='public_talk_position'>전체 메시지(최고99자)</div>
<section class="public_message">
@@ -361,7 +363,7 @@ else if($session->userGrade == 4){
<button type="button" class="load_old_message btn btn-secondary btn-block" data-msg_type="diplomacy">이전 메시지 불러오기</button>
</section>
</div></div>
<div style="clear:left;"><?=allButton($gameStor->npcmode!=0)?><?=banner()?></div>
<div style="clear:left;"><?=allButton($gameStor->npcmode==1)?><?=banner()?></div>
</div>
<?php
if ($con == 1) {
+18 -1
View File
@@ -102,7 +102,7 @@ if($session->userGrade < 5 && !$allowReset){
</div>
<div class="form-group row">
<label for="confirm_password" class="col-sm-3 col-form-label">시나리오 선택</label>
<label for="scenario_sel" class="col-sm-3 col-form-label">시나리오 선택</label>
<div class="col-sm-9">
<select class="form-control" name="scenario" size="1" id="scenario_sel">
</select>
@@ -138,6 +138,20 @@ if($session->userGrade < 5 && !$allowReset){
</div>
</div>
<div class="form-group row">
<label for="block_general_create" class="col-sm-3 col-form-label">장수 임의 생성</label>
<div class="col-sm-9">
<div id="block_general_create" class="btn-group btn-group-toggle" data-toggle="buttons">
<label class="btn btn-secondary">
<input type="radio" name="block_general_create" value="0" checked>가능
</label>
<label class="btn btn-secondary active">
<input type="radio" name="block_general_create" value="1">불가
</label>
</div>
</div>
</div>
<div class="form-group row">
<label for="npcmode" class="col-sm-3 col-form-label">NPC 빙의</label>
<div class="col-sm-9">
@@ -148,6 +162,9 @@ if($session->userGrade < 5 && !$allowReset){
<label class="btn btn-secondary active">
<input type="radio" name="npcmode" value="0" checked>불가
</label>
<label class="btn btn-secondary">
<input type="radio" name="npcmode" value="2">선택 생성 가능
</label>
</div>
</div>
</div>
+101 -100
View File
@@ -1,101 +1,102 @@
<?php
namespace sammo;
include 'lib.php';
include "func.php";
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
if (!$db->queryFirstField("SHOW TABLES LIKE 'reserved_open'")) {
Json::die([
'result'=>true,
'affected'=>0,
'status'=>'no_reserved_table'
]);
}
$reserved = $db->queryFirstRow('SELECT `date`, options FROM reserved_open ORDER BY `date` ASC LIMIT 1');
if(!$reserved){
Json::die([
'result'=>true,
'affected'=>0,
'status'=>'no_reserved'
]);
}
$reservedDate = new \DateTime($reserved['date']);
$now = new \DateTime();
$status = 'not_yet';
list($isUnited, $lastTurn) = $gameStor->getValuesAsArray(['isunited', 'turntime']);
if($isUnited === null || $lastTurn === null){
$isUnited = 2;
$lastTurn = '2000-01-01';
}
if($lastTurn !== null){
$lastTurn = new \DateTime($lastTurn);
}
if($lastTurn === null){
//이미 리셋된 상태임
}
else if(file_exists(__DIR__.'/.htaccess')){
//일단 서버는 닫혀 있음
}
else if(
$isUnited == 2 &&
$now->getTimestamp() - $lastTurn->getTimestamp() > $reservedDate->getTimestamp() - $now->getTimestamp()
){
//정지 상태 & 중간 넘음
AppConf::getList()[DB::prefix()]->closeServer();
$status = 'closed';
}
else if(
$isUnited > 0 &&
$now->getTimestamp() - $lastTurn->getTimestamp() > ($reservedDate->getTimestamp() - $now->getTimestamp()) * 2
){
//천통 & 비정지 상태 & 2/3 넘음
AppConf::getList()[DB::prefix()]->closeServer();
$status = 'closed';
}
else if($reservedDate->getTimestamp() - $now->getTimestamp() <= 60*10){
//어쨌든 간에 10분 남았다면.
AppConf::getList()[DB::prefix()]->closeServer();
$status = 'closed';
}
if($now < $reservedDate){
Json::die([
'result'=>true,
'affected'=>0,
'status'=>$status
]);
}
$options = Json::decode($reserved['options']);
$result = ResetHelper::buildScenario(
$options['turnterm'],
$options['sync'],
$options['scenario'],
$options['fiction'],
$options['extend'],
$options['npcmode'],
$options['show_img_level'],
$options['tournament_trig'],
$options['join_mode'],
$options['starttime'],
$options['autorun_user']?:null
);
$result['affected']=1;
$prefix = DB::prefix();
AppConf::getList()[$prefix]->openServer();
<?php
namespace sammo;
include 'lib.php';
include "func.php";
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
if (!$db->queryFirstField("SHOW TABLES LIKE 'reserved_open'")) {
Json::die([
'result'=>true,
'affected'=>0,
'status'=>'no_reserved_table'
]);
}
$reserved = $db->queryFirstRow('SELECT `date`, options FROM reserved_open ORDER BY `date` ASC LIMIT 1');
if(!$reserved){
Json::die([
'result'=>true,
'affected'=>0,
'status'=>'no_reserved'
]);
}
$reservedDate = new \DateTime($reserved['date']);
$now = new \DateTime();
$status = 'not_yet';
list($isUnited, $lastTurn) = $gameStor->getValuesAsArray(['isunited', 'turntime']);
if($isUnited === null || $lastTurn === null){
$isUnited = 2;
$lastTurn = '2000-01-01';
}
if($lastTurn !== null){
$lastTurn = new \DateTime($lastTurn);
}
if($lastTurn === null){
//이미 리셋된 상태임
}
else if(file_exists(__DIR__.'/.htaccess')){
//일단 서버는 닫혀 있음
}
else if(
$isUnited == 2 &&
$now->getTimestamp() - $lastTurn->getTimestamp() > $reservedDate->getTimestamp() - $now->getTimestamp()
){
//정지 상태 & 중간 넘음
ServConfig::getServerList()[DB::prefix()]->closeServer();
$status = 'closed';
}
else if(
$isUnited > 0 &&
$now->getTimestamp() - $lastTurn->getTimestamp() > ($reservedDate->getTimestamp() - $now->getTimestamp()) * 2
){
//천통 & 비정지 상태 & 2/3 넘음
ServConfig::getServerList()[DB::prefix()]->closeServer();
$status = 'closed';
}
else if($reservedDate->getTimestamp() - $now->getTimestamp() <= 60*10){
//어쨌든 간에 10분 남았다면.
ServConfig::getServerList()[DB::prefix()]->closeServer();
$status = 'closed';
}
if($now < $reservedDate){
Json::die([
'result'=>true,
'affected'=>0,
'status'=>$status
]);
}
$options = Json::decode($reserved['options']);
$result = ResetHelper::buildScenario(
$options['turnterm'],
$options['sync'],
$options['scenario'],
$options['fiction'],
$options['extend'],
$options['block_general_create'],
$options['npcmode'],
$options['show_img_level'],
$options['tournament_trig'],
$options['join_mode'],
$options['starttime'],
$options['autorun_user']?:null
);
$result['affected']=1;
$prefix = DB::prefix();
ServConfig::getServerList()[$prefix]->openServer();
Json::die($result);
@@ -4,6 +4,9 @@ namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$availableDieImmediately = false;
//로그인 검사
@@ -16,25 +19,31 @@ $gameStor = KVStorage::getStorage($db, 'game_env');
$general = $db->queryFirstRow('SELECT no,name,owner_name,npc,lastrefresh FROM general WHERE owner=%i AND npc = 0', $userID);
if(!$general){
header('location:b_myPage.php');
die();
Json::die([
'result'=>false,
'reason'=>'장수가 없습니다.'
]);
}
increaseRefresh("장수 삭제", 1);
$gameStor->cacheValues(['turnterm', 'opentime', 'turntime', 'year', 'month']);
if($gameStor->turntime <= $gameStor->opentime){
//서버 가오픈시 할 수 있는 행동
if(addTurn($general['lastrefresh'], $gameStor->turnterm, 2) <= TimeUtil::now()){
$availableDieImmediately = true;
}
if($gameStor->turntime > $gameStor->opentime){
Json::die([
'result'=>false,
'reason'=>'이미 서버가 시작되었습니다.'
]);
}
if(!$availableDieImmediately){
header('location:b_myPage.php');
die();
}
$targetTime = addTurn($general['lastrefresh'], $gameStor->turnterm, 2);
if($targetTime > TimeUtil::now()){
$targetTimeShort = substr($targetTime, 0, 19);
Json::die([
'result'=>false,
'reason'=>"아직 삭제할 수 없습니다. {$targetTimeShort} 부터 가능합니다."
]);
}
$generalObj = General::createGeneralObjFromDB($general['no']);
@@ -46,4 +55,7 @@ $josaYi = JosaUtil::pick($generalName, '이');
$generalObj->kill($db, true, "<Y>{$generalName}</>{$josaYi} 이 홀연히 모습을 <R>감추었습니다</>");
$session->logoutGame();
header('location:..');
Json::die([
'result'=>true,
'reason'=>'success'
]);
+87
View File
@@ -0,0 +1,87 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$destGeneralID = Util::getPost('destGeneralID', 'int', 0);
if(!$destGeneralID || $destGeneralID <= 0){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 장수 코드입니다'
]);
}
$session = Session::requireGameLogin([])->setReadOnly();
$db = DB::db();
increaseRefresh("시뮬레이터 추출", 1);
$userID = Session::getUserID();
$me = $db->queryFirstRow('SELECT no,nation from general where owner=%i', $userID);
$nationID = $me['nation'];
$reqColumns = [
'nation',
'name', 'officer_level', 'explevel', 'injury',
'leadership', 'horse', 'strength', 'weapon', 'intel', 'book', 'item',
'rice', 'personal', 'special2',
'crew', 'crewtype',
'atmos', 'train', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5', 'defence_train',
];
$reqRankColumns = [
'warnum', 'killnum', 'killcrew'
];
$dummyItems = [
'officer_level'=>1,
'horse'=>'None',
'weapon'=>'None',
'book'=>'None',
'item'=>'None',
'crew'=>0,
'crewtype'=>GameUnitConst::DEFAULT_CREWTYPE,
'rice'=>10000,
'train'=>GameConst::$maxTrainByCommand,
'atmos'=>GameConst::$maxTrainByCommand,
'dex1'=>0,
'dex2'=>0,
'dex3'=>0,
'dex4'=>0,
'dex5'=>0,
'defence_train'=>80,
'warnum'=>0,
'killnum'=>0,
'killcrew'=>0,
];
$rawDestGeneral = $db->queryFirstRow('SELECT %l FROM general WHERE no=%i', Util::formatListOfBackticks($reqColumns), $destGeneralID);
if($nationID == 0 || $rawDestGeneral['nation'] != $nationID){
foreach($dummyItems as $key=>$val){
$rawDestGeneral[$key] = $val;
}
}
else{
$rawRankValue = $db->queryAllLists('SELECT `type`, `value` FROM rank_data WHERE general_id = %i AND `type` IN %ls', $destGeneralID, $reqRankColumns);
foreach($rawRankValue as [$rankType, $rankValue]){
$rawDestGeneral[$rankType] = $rankValue;
}
}
foreach(['dex1', 'dex2', 'dex3', 'dex4', 'dex5'] as $dexKey){
$dex = $rawDestGeneral[$dexKey];
$rawDestGeneral[$dexKey] = getDexLevelList()[getDexLevel($dex)][0];
}
Json::die([
'result'=>true,
'reason'=>'success',
'general'=>$rawDestGeneral,
]);
+100 -93
View File
@@ -1,94 +1,101 @@
<?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);
$me = $db->queryFirstRow('SELECT no,nation,officer_level,con,turntime,belong,penalty,permission FROM general WHERE owner=%i', $userID);
$nationLevel = $db->queryFirstField('SELECT level FROM nation WHERE nation = %i', $me['nation']);
$nationID = $me['nation'];
$con = checkLimit($me['con']);
if($con >= 2) {
Json::die([
'result'=>false,
'reason'=>"접속 제한중입니다. 1턴 이내에 너무 많은 갱신을 하셨습니다. (다음 접속 가능 시각 : {$me['turntime']})"
]);
}
$permission = checkSecretPermission($me);
if($permission < 0){
Json::die([
'result'=>false,
'reason'=>'국가에 소속되어있지 않습니다.'
]);
echo '국가에 소속되어있지 않습니다.';
die();
}
else if ($permission < 1) {
Json::die([
'result'=>false,
'reason'=>'수뇌부가 아니거나 사관년도가 부족합니다.'
]);
die();
}
$date = TimeUtil::now();
// 명령 목록
[$year, $month, $turnterm] = $gameStor->getValuesAsArray(['year', 'month', 'turnterm']);
$lv = getNationChiefLevel($nationLevel);
$turn = [];
$generals = [];
foreach($db->query('SELECT no,name,turntime,npc,city,nation,officer_level FROM general WHERE nation = %i AND officer_level >= 5',$nationID) as $rawGeneral){
$generals[$rawGeneral['officer_level']] = new General($rawGeneral, null, null, null, $year, $month, false);
}
$nationTurnList = [];
foreach(
$db->queryAllLists(
'SELECT officer_level, turn_idx, action, arg, brief FROM nation_turn WHERE nation_id = %i ORDER BY officer_level DESC, turn_idx ASC',
$me['nation']
) as [$officer_level, $turn_idx, $action, $arg, $brief]
){
if(!key_exists($officer_level, $nationTurnList)){
$nationTurnList[$officer_level] = [];
}
$nationTurnList[$officer_level][$turn_idx] = $brief;
}
$nationTurnBrief = [];
foreach($nationTurnList as $officer_level=>$turnBrief){
if(!key_exists($officer_level, $generals)){
continue;
}
$general = $generals[$officer_level];
$nationTurnBrief[$officer_level] = [
'name'=>$general->getName(),
'turnTime'=>$general->getTurnTime($general::TURNTIME_FULL),
'officerLevelText'=>getOfficerLevelText($general->getVar('officer_level'), $nationLevel),
'npcType'=>$general->getNPCType(),
'turn'=>$turnBrief
];
}
$date = substr(TimeUtil::now(), 14);
Json::die([
'result'=>true,
'reason'=>'success',
'date'=>$date,
'nationTurnBrief'=>$nationTurnBrief,
'isChief'=>($me['officer_level'] > 4),
'turnTerm'=>$turnterm
<?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);
$me = $db->queryFirstRow('SELECT no,nation,officer_level,con,turntime,belong,penalty,permission FROM general WHERE owner=%i', $userID);
$nationLevel = $db->queryFirstField('SELECT level FROM nation WHERE nation = %i', $me['nation']);
$nationID = $me['nation'];
$con = checkLimit($me['con']);
if($con >= 2) {
Json::die([
'result'=>false,
'reason'=>"접속 제한중입니다. 1턴 이내에 너무 많은 갱신을 하셨습니다. (다음 접속 가능 시각 : {$me['turntime']})"
]);
}
$permission = checkSecretPermission($me);
if($permission < 0){
Json::die([
'result'=>false,
'reason'=>'국가에 소속되어있지 않습니다.'
]);
echo '국가에 소속되어있지 않습니다.';
die();
}
else if ($permission < 1) {
Json::die([
'result'=>false,
'reason'=>'수뇌부가 아니거나 사관년도가 부족합니다.'
]);
die();
}
$date = TimeUtil::now();
// 명령 목록
[$year, $month, $turnterm] = $gameStor->getValuesAsArray(['year', 'month', 'turnterm']);
$lv = getNationChiefLevel($nationLevel);
$turn = [];
$generals = [];
foreach($db->query('SELECT no,name,turntime,npc,city,nation,officer_level FROM general WHERE nation = %i AND officer_level >= 5',$nationID) as $rawGeneral){
$generals[$rawGeneral['officer_level']] = new General($rawGeneral, null, null, null, $year, $month, false);
}
$nationTurnList = [];
foreach(
$db->queryAllLists(
'SELECT officer_level, turn_idx, action, arg, brief FROM nation_turn WHERE nation_id = %i ORDER BY officer_level DESC, turn_idx ASC',
$me['nation']
) as [$officer_level, $turn_idx, $action, $arg, $brief]
){
if(!key_exists($officer_level, $nationTurnList)){
$nationTurnList[$officer_level] = [];
}
$nationTurnList[$officer_level][$turn_idx] = $brief;
}
$nationTurnBrief = [];
foreach($nationTurnList as $officer_level=>$turnBrief){
if(!key_exists($officer_level, $generals)){
$nationTurnBrief[$officer_level] = [
'name'=>null,
'turnTime'=>null,
'officerLevelText'=>getOfficerLevelText($officer_level, $nationLevel),
'npcType'=>null,
'turn'=>$turnBrief
];
continue;
}
$general = $generals[$officer_level];
$nationTurnBrief[$officer_level] = [
'name'=>$general->getName(),
'turnTime'=>$general->getTurnTime($general::TURNTIME_FULL),
'officerLevelText'=>getOfficerLevelText($general->getVar('officer_level'), $nationLevel),
'npcType'=>$general->getNPCType(),
'turn'=>$turnBrief
];
}
$date = substr(TimeUtil::now(), 14);
Json::die([
'result'=>true,
'reason'=>'success',
'date'=>$date,
'nationTurnBrief'=>$nationTurnBrief,
'isChief'=>($me['officer_level'] > 4),
'turnTerm'=>$turnterm
]);
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
//로그인 검사
$session = Session::requireGameLogin([]);
$generalID = Session::getGeneralID();
$db = DB::db();
$rawList = Util::convertArrayToDict($db->query('SELECT no, name, npc, nation FROM general'), 'no');
$nationID = $rawList[$generalID]['nation'];
$result = [
'result'=>true,
'reason'=>'success',
'nationID'=>$nationID,
'generalID'=>$generalID,
'column'=>['no', 'name', 'npc']
];
$resultItem = [];
foreach(Util::arrayGroupBy($rawList, 'nation') as $subNationID=>$generals){
$subNation = [];
foreach($generals as $general){
$subNation[] = [$general['no'], $general['name'], $general['npc']];
}
$resultItem[$subNationID] = $subNation;
}
$result['list'] = $resultItem;
$result['nation'] = Util::convertArrayToDict($db->query('SELECT nation, name, color FROM nation'), 'nation');
Json::die($result);
+109 -109
View File
@@ -1,109 +1,109 @@
<?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);
<?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);
+95 -77
View File
@@ -1,4 +1,5 @@
<?php
namespace sammo;
//통합 세력장수&암행부 viewer
@@ -11,145 +12,162 @@ $session = Session::requireGameLogin([])->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
$reqType = Util::getPost('req', 'int', 1);
$reqForce = Util::getPost('force', 'bool', false);
$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, nation, officer_level, permission, penalty FROM general WHERE owner=%i', $userID);
$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턴 이내에 너무 많은 갱신을 하셨습니다.'
'result' => false,
'reason' => '접속 제한중입니다. 1턴 이내에 너무 많은 갱신을 하셨습니다.'
]);
}
$nationID = $me['nation'];
$permission = checkSecretPermission($me, true);
if($reqForce && $reqType > $permission){
if ($reqForce && $reqType > $permission) {
Json::die([
'result'=>false,
'reason'=>'권한이 부족합니다.'
'result' => false,
'reason' => '권한이 부족합니다.'
]);
}
$permission = min($reqType, $permission);
$nationArr = getNationStaticInfo($nationID);
$viewColumns = [
'no'=>1,
'name'=>1,
'owner_name'=>9,
'nation'=>1,
'city'=>1,
'officer_level'=>9,
'npc'=>1,
'defence_train'=>2,
'troop'=>2,
'injury'=>1,
'leadership'=>1,
'strength'=>1,
'intel'=>1,
'experience'=>1,
'explevel'=>1,
'dedication'=>1,
'dedlevel'=>1,
'gold'=>1,
'rice'=>1,
'crewtype'=>2,
'crew'=>2,
'train'=>2,
'atmos'=>2,
'killturn'=>1,
'turntime'=>2,
'picture'=>1,
'imgsvr'=>1,
'age'=>1,
'special'=>1,
'special2'=>1,
'personal'=>1,
'horse'=>3,
'weapon'=>3,
'book'=>3,
'item'=>3,
'connect'=>1
'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'=>1,
'officerLevelText'=>1,
'lbonus'=>1,
'ownerName'=>1,
'honorText'=>1,
'expLevelText'=>1,
'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 $rawGeneral['officer_level'];
'officerLevel' => function ($rawGeneral){
return getOfficerLevel($rawGeneral);
},
'special'=>function($rawGeneral){
'special' => function ($rawGeneral) {
return getGeneralSpecialDomesticName($rawGeneral['special']);
},
'special2'=>function($rawGeneral){
'special2' => function ($rawGeneral) {
return getGeneralSpecialWarName($rawGeneral['special2']);
},
'personal'=>function($rawGeneral){
'personal' => function ($rawGeneral) {
return getGenChar($rawGeneral['personal']);
},
'lbonus'=>function($rawGeneral)use($nationArr){
'lbonus' => function ($rawGeneral) use ($nationArr) {
return calcLeadershipBonus($rawGeneral['officer_level'], $nationArr['level']);
},
'ownerName'=>function($rawGeneral){
if($rawGeneral['npc']!=1){
'ownerName' => function ($rawGeneral) {
if ($rawGeneral['npc'] != 1) {
return null;
}
return $rawGeneral['owner_name'];
},
'officerLevelText'=>function($rawGeneral)use($nationArr){
return getOfficerLevelText($rawGeneral['officer_level'], $nationArr['level']);
'officerLevelText' => function ($rawGeneral) use ($nationArr) {
$level = getOfficerLevel($rawGeneral);
return getOfficerLevelText($level, $nationArr['level']);
},
'honorText'=>function($rawGeneral){
'honorText' => function ($rawGeneral) {
return getHonor($rawGeneral['experience']);
},
'dedLevelText'=>function($rawGeneral){
'dedLevelText' => function ($rawGeneral) {
return getDedLevelText($rawGeneral['dedLevel']);
},
'turntime'=>function($rawGeneral){
'turntime' => function ($rawGeneral) {
//'0000-00-00 11:23';
return substr($rawGeneral['turntime'], 11, 5);
}
];
$queryColumns = General::mergeQueryColumn(array_keys($viewColumns), 1);
[$queryColumns, $rankColumns] = General::mergeQueryColumn(array_keys($viewColumns), 1);
$rawGeneralList = Util::convertArrayToDict($db->queryAllLists('SELECT %lb from general WHERE nation = %i', $queryColumns, $nationID), 'no');
$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){
foreach ($viewColumns as $column => $reqPermission) {
if ($reqPermission > $permission) {
continue;
}
$resultColumns[] = $column;
}
foreach($customViewColumns as $column=>$reqPermission){
if($reqPermission > $permission){
foreach ($customViewColumns as $column => $reqPermission) {
if ($reqPermission > $permission) {
continue;
}
$resultColumns[] = $column;
}
foreach($rawGeneralList as $rawGeneral){
foreach ($rawGeneralList as $rawGeneral) {
//General 생성?
$item = [];
foreach($resultColumns as $column){
$value = $rawGeneral[$column];
if(key_exists($column, $specialViewFilter)){
foreach ($resultColumns as $column) {
if (key_exists($column, $specialViewFilter)) {
$value = $specialViewFilter[$column]($rawGeneral);
}
else{
$value = $rawGeneral[$column];
}
$item[] = $value;
}
@@ -157,9 +175,9 @@ foreach($rawGeneralList as $rawGeneral){
}
$result = [
'result'=>true,
'column'=>$resultColumns,
'list'=>$generalList,
'result' => true,
'column' => $resultColumns,
'list' => $generalList,
];
Json::die($result);
+1 -1
View File
@@ -37,7 +37,7 @@ list(
$npcmode
) = $gameStor->getValuesAsArray(['maxgeneral', 'turnterm', 'npcmode']);
if(!$npcmode){
if($npcmode!=1){
Json::die([
'result'=>false,
'reason'=>'빙의 가능한 서버가 아닙니다'
+90
View File
@@ -0,0 +1,90 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
function sortTokens(&$tokens){
usort($tokens, function($lhs, $rhs){
return array_sum($lhs['dex'])<=>array_sum($rhs['dex']);
});
}
function putInfoText(&$info){
if(key_exists('specialDomestic', $info)){
$class = buildGeneralSpecialDomesticClass($info['specialDomestic']);
$info['specialDomesticName'] = $class->getName();
$info['specialDomesticInfo'] = $class->getInfo();
}
if(key_exists('specialWar', $info)){
$class = buildGeneralSpecialDomesticClass($info['specialWar']);
$info['specialWarName'] = $class->getName();
$info['specialWarInfo'] = $class->getInfo();
}
}
$session = Session::requireLogin([])->setReadOnly();
$userID = Session::getUserID();
$oNow = new \DateTimeImmutable();
$now = $oNow->format('Y-m-d H:i:s');
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$npcmode = $gameStor->getValue('npcmode');
if($npcmode!=2){
Json::die([
'result'=>false,
'reason'=>'선택 가능한 서버가 아닙니다'
]);
}
$rawGeneral = $db->queryFirstRow('SELECT no, aux FROM general WHERE `owner` = %i', $userID);
if($rawGeneral){
$generalAux = Json::decode($rawGeneral['aux']);
if(key_exists('next_change', $generalAux)&& $generalAux['next_change'] > $now){
Json::die([
'result'=>false,
'reason'=>'아직 다시 고를 수 없습니다'
]);
}
}
$tokens = $db->query('SELECT unique_name, reserved_until, info FROM `select_pool` WHERE `owner`=%i AND `reserved_until`>=%s', $userID, $now);
if($tokens){
$pick = [];
$valid_until = null;
$specialInfo = [];
foreach($tokens as $token){
$valid_until = $token['reserved_until'];
$info = Json::decode($token['info']);
putInfoText($info);
$info['uniqueName'] = $token['unique_name'];
$pick[] = $info;
}
sortTokens($pick);//좀 무식하지만..
Json::die([
'result'=>true,
'pick'=>$pick,
'validUntil'=>$valid_until
]);
}
$pick = [];
$valid_until = null;
foreach(pickGeneralFromPool($db, $userID, 14) as $pickObj){
$valid_until = $pickObj->getValidUntil();
$info = $pickObj->getInfo();
putInfoText($info);
$pick[] = $info;
}
sortTokens($pick);//좀 무식하지만..
Json::die([
'result'=>true,
'pick'=>$pick,
'validUntil'=>$valid_until
]);
+214 -208
View File
@@ -1,209 +1,215 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$session = Session::requireLogin([])->setReadOnly();
if(!class_exists('\\sammo\\DB')){
Json::die([
'result'=>false,
'reason'=>'DB리셋 필요'
]);
}
$serverName = DB::prefix();
$serverAcl = $session->acl[$serverName]??[];
$allowReset = in_array('reset', $serverAcl);
$allowFullReset = in_array('fullReset',$serverAcl);
$allowReset |= $allowFullReset;
$reserve_open = Util::getPost('reserve_open');
if($reserve_open && $reserve_open < date('Y-m-d H:i')){
Json::die([
'result'=>false,
'reason'=>'현재 시간보다 이전 시간대를 예약 시간으로 지정했습니다.'
]);
}
$pre_reserve_open = Util::getPost('pre_reserve_open');
if($pre_reserve_open && !$reserve_open){
Json::die([
'result'=>false,
'reason'=>'가오픈 예약을 위해선 오픈 예약을 지정해야합니다.'
]);
}
if($pre_reserve_open && $pre_reserve_open >= $reserve_open){
Json::die([
'result'=>false,
'reason'=>'가오픈 시간이 오픈 예약 시점보다 이전이어야 합니다.'
]);
}
if($session->userGrade < 5 && !$allowReset){
Json::die([
'result'=>false,
'reason'=>'관리자 아님'
]);
}
$v = new Validator($_POST);
$v->rule('required', [
'turnterm',
'sync',
'scenario',
'fiction',
'extend',
'join_mode',
'npcmode',
'show_img_level',
'autorun_user_minutes'
])->rule('integer', [
'turnterm',
'sync',
'scenario',
'fiction',
'extend',
'npcmode',
'show_img_level',
'tournament_trig',
'autorun_user_minutes'
])->rule('in', 'join_mode', ['onlyRandom', 'full']);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>$v->errorStr()
]);
}
$allowReset = true;
if($session->userGrade < 5 && !$allowFullReset){
//리셋 가능한 조건인지 테스트
$allowReset = false;
if(file_exists(__DIR__.'/.htaccess')){
$allowReset = true;
}
else{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
if($gameStor->isunited){
$allowReset = true;
}
}
}
if(!$allowReset){
Json::die([
'result'=>false,
'reason'=>'부족한 권한: 서버가 닫혀있거나, 천통되어 있을 경우에만 리셋 가능합니다.'
]);
}
$turnterm = (int)$_POST['turnterm'];
$sync = (int)$_POST['sync'];
$scenario = (int)$_POST['scenario'];
$fiction = (int)$_POST['fiction'];
$extend = (int)$_POST['extend'];
$npcmode = (int)$_POST['npcmode'];
$show_img_level = (int)$_POST['show_img_level'];
$tournament_trig = (int)$_POST['tournament_trig'];
$join_mode = $_POST['join_mode'];
$autorun_user_minutes = (int)$_POST['autorun_user_minutes'];
$autorun_user_options = [];
foreach(Util::getPost('autorun_user', 'array_string', []) as $autorun_option){
$autorun_user_options[$autorun_option] = 1;
}
if($autorun_user_minutes > 0 && !$autorun_user_options){
Json::die([
'result'=>false,
'reason'=>'적어도 자동 행동 중 하나는 선택을 해야합니다.'
]);
}
if($autorun_user_minutes < 0){
Json::die([
'result'=>false,
'reason'=>'자동 행동 기한이 0보다 작을 수 없습니다.'
]);
}
$autorun_user = $autorun_user_minutes?[
'limit_minutes'=>$autorun_user_minutes,
'options'=>$autorun_user_options
]:null;
if($reserve_open){
$reserve_open = new \DateTime($reserve_open);
$db = DB::db();
if (!$db->queryFirstField("SHOW TABLES LIKE 'storage'")) {
$clearResult = ResetHelper::clearDB();
if(!$clearResult['result']){
Json::die($clearResult);
}
}
if (!$db->queryFirstField("SHOW TABLES LIKE 'reserved_open'")) {
Json::die([
'result'=>false,
'reason'=>'예약 테이블이 없음!'
]);
}
$scenarioObj = new Scenario($scenario, true);
$open_date = $reserve_open->format('Y-m-d H:i:s');
$reserveInfo = [
'turnterm'=>$turnterm,
'sync'=>$sync,
'scenario'=>$scenario,
'scenarioName'=>$scenarioObj->getTitle(),
'fiction'=>$fiction,
'extend'=>$extend,
'npcmode'=>$npcmode,
'show_img_level'=>$show_img_level,
'tournament_trig'=>$tournament_trig,
'gameConf'=>$scenarioObj->getGameConf(),
'join_mode'=>$join_mode,
'starttime'=>$open_date,
'autorun_user'=>$autorun_user
];
if($pre_reserve_open){
$pre_reserve_open = new \DateTime($pre_reserve_open);
$open_date = $pre_reserve_open->format('Y-m-d H:i:s');
}
$db->delete('reserved_open', true);
$db->insert('reserved_open', [
'options'=>Json::encode($reserveInfo),
'date'=>$open_date
]);
AppConf::getList()[DB::prefix()]->closeServer();
Json::die([
'result'=>true,
'reason'=>'예약'
]);
}
Json::die(ResetHelper::buildScenario(
$turnterm,
$sync,
$scenario,
$fiction,
$extend,
$npcmode,
$show_img_level,
$tournament_trig,
$join_mode,
TimeUtil::now(),
$autorun_user
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$session = Session::requireLogin([])->setReadOnly();
if(!class_exists('\\sammo\\DB')){
Json::die([
'result'=>false,
'reason'=>'DB리셋 필요'
]);
}
$serverName = DB::prefix();
$serverAcl = $session->acl[$serverName]??[];
$allowReset = in_array('reset', $serverAcl);
$allowFullReset = in_array('fullReset',$serverAcl);
$allowReset |= $allowFullReset;
$reserve_open = Util::getPost('reserve_open');
if($reserve_open && $reserve_open < date('Y-m-d H:i')){
Json::die([
'result'=>false,
'reason'=>'현재 시간보다 이전 시간대를 예약 시간으로 지정했습니다.'
]);
}
$pre_reserve_open = Util::getPost('pre_reserve_open');
if($pre_reserve_open && !$reserve_open){
Json::die([
'result'=>false,
'reason'=>'가오픈 예약을 위해선 오픈 예약을 지정해야합니다.'
]);
}
if($pre_reserve_open && $pre_reserve_open >= $reserve_open){
Json::die([
'result'=>false,
'reason'=>'가오픈 시간이 오픈 예약 시점보다 이전이어야 합니다.'
]);
}
if($session->userGrade < 5 && !$allowReset){
Json::die([
'result'=>false,
'reason'=>'관리자 아님'
]);
}
$v = new Validator($_POST);
$v->rule('required', [
'turnterm',
'sync',
'scenario',
'fiction',
'extend',
'block_general_create',
'join_mode',
'npcmode',
'show_img_level',
'autorun_user_minutes'
])->rule('integer', [
'turnterm',
'sync',
'scenario',
'fiction',
'extend',
'block_general_create',
'npcmode',
'show_img_level',
'tournament_trig',
'autorun_user_minutes'
])->rule('in', 'join_mode', ['onlyRandom', 'full']);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>$v->errorStr()
]);
}
$allowReset = true;
if($session->userGrade < 5 && !$allowFullReset){
//리셋 가능한 조건인지 테스트
$allowReset = false;
if(file_exists(__DIR__.'/.htaccess')){
$allowReset = true;
}
else{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
if($gameStor->isunited){
$allowReset = true;
}
}
}
if(!$allowReset){
Json::die([
'result'=>false,
'reason'=>'부족한 권한: 서버가 닫혀있거나, 천통되어 있을 경우에만 리셋 가능합니다.'
]);
}
$turnterm = (int)$_POST['turnterm'];
$sync = (int)$_POST['sync'];
$scenario = (int)$_POST['scenario'];
$fiction = (int)$_POST['fiction'];
$extend = (int)$_POST['extend'];
$npcmode = (int)$_POST['npcmode'];
$block_general_create = (bool)$_POST['block_general_create'];
$show_img_level = (int)$_POST['show_img_level'];
$tournament_trig = (int)$_POST['tournament_trig'];
$join_mode = $_POST['join_mode'];
$autorun_user_minutes = (int)$_POST['autorun_user_minutes'];
$autorun_user_options = [];
foreach(Util::getPost('autorun_user', 'array_string', []) as $autorun_option){
$autorun_user_options[$autorun_option] = 1;
}
if($autorun_user_minutes > 0 && !$autorun_user_options){
Json::die([
'result'=>false,
'reason'=>'적어도 자동 행동 중 하나는 선택을 해야합니다.'
]);
}
if($autorun_user_minutes < 0){
Json::die([
'result'=>false,
'reason'=>'자동 행동 기한이 0보다 작을 수 없습니다.'
]);
}
$autorun_user = $autorun_user_minutes?[
'limit_minutes'=>$autorun_user_minutes,
'options'=>$autorun_user_options
]:null;
if($reserve_open){
$reserve_open = new \DateTime($reserve_open);
$db = DB::db();
if (!$db->queryFirstField("SHOW TABLES LIKE 'storage'")) {
$clearResult = ResetHelper::clearDB();
if(!$clearResult['result']){
Json::die($clearResult);
}
}
if (!$db->queryFirstField("SHOW TABLES LIKE 'reserved_open'")) {
Json::die([
'result'=>false,
'reason'=>'예약 테이블이 없음!'
]);
}
$scenarioObj = new Scenario($scenario, true);
$open_date = $reserve_open->format('Y-m-d H:i:s');
$reserveInfo = [
'turnterm'=>$turnterm,
'sync'=>$sync,
'scenario'=>$scenario,
'scenarioName'=>$scenarioObj->getTitle(),
'fiction'=>$fiction,
'extend'=>$extend,
'block_general_create'=>$block_general_create,
'npcmode'=>$npcmode,
'show_img_level'=>$show_img_level,
'tournament_trig'=>$tournament_trig,
'gameConf'=>$scenarioObj->getGameConf(),
'join_mode'=>$join_mode,
'starttime'=>$open_date,
'autorun_user'=>$autorun_user
];
if($pre_reserve_open){
$pre_reserve_open = new \DateTime($pre_reserve_open);
$open_date = $pre_reserve_open->format('Y-m-d H:i:s');
}
$db->delete('reserved_open', true);
$db->insert('reserved_open', [
'options'=>Json::encode($reserveInfo),
'date'=>$open_date
]);
ServConfig::getServerList()[DB::prefix()]->closeServer();
Json::die([
'result'=>true,
'reason'=>'예약'
]);
}
Json::die(ResetHelper::buildScenario(
$turnterm,
$sync,
$scenario,
$fiction,
$extend,
$block_general_create,
$npcmode,
$show_img_level,
$tournament_trig,
$join_mode,
TimeUtil::now(),
$autorun_user
));
+102 -102
View File
@@ -1,103 +1,103 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$session = Session::requireLogin([])->setReadOnly();
if($session->userGrade < 6){
Json::die([
'result'=>false,
'reason'=>'관리자 아님'
]);
}
$fullReset = Util::getPost('full_reset', 'bool', false);
$host = Util::getPost('db_host');
$port = Util::getPost('db_port', 'int');
$username = Util::getPost('db_id');
$password = Util::getPost('db_pw');
$dbName = Util::getPost('db_name');
if(!$host || !$port || !$username || !$password || !$dbName){
Json::die([
'result'=>false,
'reason'=>'입력 값이 올바르지 않습니다'
]);
}
if($fullReset && class_exists('\\sammo\\DB')){
$mysqli_obj = DB::db()->get();
if($mysqli_obj->multi_query(file_get_contents(__DIR__.'/sql/reset.sql'))){
while(true){
if (!$mysqli_obj->more_results()) {
break;
}
if(!$mysqli_obj->next_result()){
break;
}
}
}
}
if($fullReset){
FileUtil::delInDir(__DIR__."/logs");
FileUtil::delInDir(__DIR__."/data");
if(file_exists(__DIR__.'/d_setting/DB.php')){
@unlink(__DIR__.'/d_setting/DB.php');
}
if(file_exists(__DIR__.'/d_setting/UniqueConst.php')){
@unlink(__DIR__.'/d_setting/UniqueConst.php');
}
}
function dbConnFail($params){
Json::die([
'result'=>false,
'reason'=>'DB 접속에 실패했습니다.'
]);
}
$db = new \MeekroDB($host,$username,$password,$dbName,$port,'utf8mb4');
$db->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true;
$db->throw_exception_on_nonsql_error = false;
$db->nonsql_error_handler = 'dbConnFail';
$mysqli_obj = $db->get(); //로그인에 실패할 경우 자동으로 dbConnFail()이 실행됨.
$prefix = basename(__DIR__);
$result = Util::generateFileUsingSimpleTemplate(
__DIR__.'/d_setting/DB.orig.php',
__DIR__.'/d_setting/DB.php',[
'host'=>$host,
'user'=>$username,
'password'=>$password,
'dbName'=>$dbName,
'port'=>$port,
'prefix'=>$prefix
], true
);
if($result !== true){
Json::die([
'result'=>false,
'reason'=>$result
]);
}
ResetHelper::clearDB();
AppConf::getList()[$prefix]->closeServer();
Json::die([
'result'=>true,
'reason'=>'success'
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$session = Session::requireLogin([])->setReadOnly();
if($session->userGrade < 6){
Json::die([
'result'=>false,
'reason'=>'관리자 아님'
]);
}
$fullReset = Util::getPost('full_reset', 'bool', false);
$host = Util::getPost('db_host');
$port = Util::getPost('db_port', 'int');
$username = Util::getPost('db_id');
$password = Util::getPost('db_pw');
$dbName = Util::getPost('db_name');
if(!$host || !$port || !$username || !$password || !$dbName){
Json::die([
'result'=>false,
'reason'=>'입력 값이 올바르지 않습니다'
]);
}
if($fullReset && class_exists('\\sammo\\DB')){
$mysqli_obj = DB::db()->get();
if($mysqli_obj->multi_query(file_get_contents(__DIR__.'/sql/reset.sql'))){
while(true){
if (!$mysqli_obj->more_results()) {
break;
}
if(!$mysqli_obj->next_result()){
break;
}
}
}
}
if($fullReset){
FileUtil::delInDir(__DIR__."/logs");
FileUtil::delInDir(__DIR__."/data");
if(file_exists(__DIR__.'/d_setting/DB.php')){
@unlink(__DIR__.'/d_setting/DB.php');
}
if(file_exists(__DIR__.'/d_setting/UniqueConst.php')){
@unlink(__DIR__.'/d_setting/UniqueConst.php');
}
}
function dbConnFail($params){
Json::die([
'result'=>false,
'reason'=>'DB 접속에 실패했습니다.'
]);
}
$db = new \MeekroDB($host,$username,$password,$dbName,$port,'utf8mb4');
$db->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true;
$db->throw_exception_on_nonsql_error = false;
$db->nonsql_error_handler = 'dbConnFail';
$mysqli_obj = $db->get(); //로그인에 실패할 경우 자동으로 dbConnFail()이 실행됨.
$prefix = basename(__DIR__);
$result = Util::generateFileUsingSimpleTemplate(
__DIR__.'/d_setting/DB.orig.php',
__DIR__.'/d_setting/DB.php',[
'host'=>$host,
'user'=>$username,
'password'=>$password,
'dbName'=>$dbName,
'port'=>$port,
'prefix'=>$prefix
], true
);
if($result !== true){
Json::die([
'result'=>false,
'reason'=>$result
]);
}
ResetHelper::clearDB();
ServConfig::getServerList()[$prefix]->closeServer();
Json::die([
'result'=>true,
'reason'=>'success'
]);
+83
View File
@@ -0,0 +1,83 @@
<?php
namespace sammo;
use Nette\Caching\Cache;
include "lib.php";
include "func.php";
if(!class_exists('\\sammo\\UniqueConst')){
Json::die([
'result'=>false,
'reason'=>'서버 초기화되지 않음'
]);
}
if(!prepareDir('data/file_cache')){
Json::die([
'result'=>false,
'reason'=>'cache 불가'
]);
}
$storage = new \Nette\Caching\Storages\FileStorage('data/file_cache');
$cache = new Cache($storage);
$serverID = UniqueConst::$serverID;
$mapInfo = $cache->load("recent_map");
//로그인 검사
$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();
}
Json::die($mapInfo['data'], 0);
}
$defaultPost = [
'year' => null,
'month' => null,
'aux' => null,
'neutralView' => true,
'showMe' => false,
];
$history = formatHistoryToHTML(getGlobalHistoryLogRecent(10));
$rawMap = getWorldMap([
'year' => null,
'month' => null,
'aux' => null,
'neutralView' => true,
'showMe' => false,
]);
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$mapTheme = $gameStor->map_theme ?? 'che';
$rawMap['history'] = $history;
$rawMap['theme'] = $mapTheme;
$etag = hash('sha256', $serverID.$now);
$map = [
'etag'=>$etag,
'timestamp'=>$now,
'data'=>$rawMap,
];
$cache->save("recent_map", $map);
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $now)." GMT");
header("Etag: $etag");
Json::die($map['data'], 0);
+360 -359
View File
@@ -1,360 +1,361 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$action = Util::getPost('action');
$officerLevel = Util::getPost('officerLevel', 'int');
$destGeneralID = Util::getPost('destGeneralID', 'int');
$destCityID = Util::getPost('destCityID', 'int');
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheValues(['startyear','year','month','scenario']);
$me = $db->queryFirstRow('SELECT no,nation,officer_level from general where owner=%i', $userID);
$myOfficerLevel = $me['officer_level'];
$nationID = $me['nation'];
//수뇌가 아니면 아무것도 할 수 없음
if($myOfficerLevel < 5){
Json::die([
'result'=>false,
'reason'=>'수뇌가 아닙니다.'
]);
}
if($action === '추방' && $destGeneralID==0){
Json::die([
'result'=>false,
'reason'=>'장수가 지정되지 않았습니다.'
]);
}
if($destGeneralID==0){
$general = new DummyGeneral(true);
}
else{
$general = General::createGeneralObjFromDB($destGeneralID, [
'name', 'leadership', 'strength', 'intel', 'gold','rice',
'troop','officer_level','npc','picture','imgsvr',
'permission','penalty','belong', 'crewtype',
'experience', 'dedication', 'betray', 'dedlevel', 'explevel', 'makelimit',
], 1);
if($general instanceof DummyGeneral){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 장수입니다.'
]);
}
if($nationID != $general->getNationID()){
Json::die([
'result'=>false,
'reason'=>'아국 장수가 아닙니다'
]);
}
}
if($officerLevel == 12){
Json::die([
'result'=>false,
'reason'=>'군주를 대상으로 할 수 없습니다.'
]);
}
function do수뇌임명(General $general, int $targetOfficerLevel):?string{
$generalID = $general->getID();
$nationID = $general->getNationID();
$db = DB::db();
[$chiefSet, $nationLevel] = $db->queryFirstList('SELECT chief_set,level FROM nation WHERE nation = %i',$nationID);
// 임명가능 레벨
$lv = getNationChiefLevel($nationLevel);
if($targetOfficerLevel < $lv){
return '임명불가능한 관직입니다.';
}
if(isOfficerSet($chiefSet, $targetOfficerLevel)){
return '지금은 임명할 수 없습니다.';
}
//기존 장수 일반으로
$db->update('general', [
'officer_level'=>1,
'officer_city'=>0,
], 'nation=%i AND officer_level=%i AND no!=%i', $nationID, $targetOfficerLevel, $generalID);
if($targetOfficerLevel === 11){
}
else if($targetOfficerLevel % 2 == 0){
if($general->getVar('strength') < GameConst::$chiefStatMin){
return '무력이 부족합니다.';
}
}
else{
if($general->getVar('intel') < GameConst::$chiefStatMin){
return '지력이 부족합니다.';
}
}
//신임 장수
$general->setVar('officer_level', $targetOfficerLevel);
$general->setVar('officer_city', 0);
$db->update('nation', [
'chief_set'=> $db->sqleval('chief_set | %i', doOfficerSet(0, $targetOfficerLevel)),
], 'nation=%i', $nationID);
$general->applyDB($db);
return null;
}
function do도시임명(General $general, int $cityID, int $targetOfficerLevel):?string{
$nationID = $general->getNationID();
$db = DB::db();
if(CityConst::byID($cityID) === null){
return '올바르지 않은 도시입니다';
}
$officerSet = $db->queryFirstField('SELECT officer_set FROM city WHERE nation=%i AND city=%i', $nationID, $cityID);
if($officerSet === null){
return '아국 도시가 아닙니다';
}
if(isOfficerSet($officerSet, $targetOfficerLevel)){
return '이미 다른 장수가 임명되어있습니다';
}
//기존 장수 일반으로
$db->update('general', [
'officer_level'=>1,
'officer_city'=>0,
], 'officer_level=%i AND officer_city=%i AND no!=%i', $targetOfficerLevel, $cityID, $general->getID());
if($general instanceof DummyGeneral){
return null;
}
if($targetOfficerLevel === 4 && $general->getVar('strength') < GameConst::$chiefStatMin){
return '무력이 부족합니다.';
}
if($targetOfficerLevel === 3 && $general->getVar('intel') < GameConst::$chiefStatMin){
return '지력이 부족합니다.';
}
//신임 장수
$db->update('city', [
'officer_set'=>$db->sqleval('officer_set | %i', doOfficerSet(0, $targetOfficerLevel)),
], 'city=%i AND nation=%i', $cityID, $nationID);
$general->setVar('officer_level', $targetOfficerLevel);
$general->setVar('officer_city', $cityID);
$general->applyDB($db);
return null;
}
function do추방(General $general, int $myOfficerLevel):?string{
$generalID = $general->getID();
$generalName = $general->getVar('name');
$nationID = $general->getNationID();
//추방할사람이 외교권자이면 불가
$permission = checkSecretPermission($general->getRaw());
if($permission == 4){
return '외교권자는 추방할 수 없습니다.';
}
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$env = $gameStor->getValues(['startyear','year','month','scenario']);
$nation = $db->queryFirstRow('SELECT name,chief_set,color FROM nation WHERE nation=%i', $nationID);
$nationName = $nation['name'];
$logger = $general->getLogger();
//이미 지정했다면 무시
if(isOfficerSet($nation['chief_set'], $myOfficerLevel) || ($myOfficerLevel == 0 && $myOfficerLevel == 12)) {
return '이미 추방 권한을 사용했습니다.';
}
$gold = 0;
$rice = 0;
// 금쌀1000이상은 남김
if($general->getVar('gold') > GameConst::$defaultGold) {
$gold = $general->getVar('gold') - GameConst::$defaultGold;
$general->setVar('gold', GameConst::$defaultGold);
}
if($general->getVar('rice') > GameConst::$defaultRice) {
$rice = $general->getVar('rice') - GameConst::$defaultRice;
$general->setVar('rice', GameConst::$defaultRice);
}
$general->setVar('nation', 0);
$general->setVar('officer_level', 0);
$general->setVar('officer_city', 0);
$general->setVar('belong', 0);
$oldMakeLimit = $general->getVar('makelimit');
$general->setVar('makelimit', 12);
$general->setVar('permission', 'normal');
$josaYi = JosaUtil::pick($generalName, '이');
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <D><b>{$nationName}</b></>에서 <R>추방</>당했습니다.");
$logger->pushGeneralActionLog("<D><b>{$nationName}</b></>에서 <R>추방</>당했습니다.", ActionLogger::PLAIN);
// 명성/공헌 N*10%감소
if($env['year'] <= $env['startyear'] && $general->getNPCType() < 2){
$general->setVar('makelimit', $oldMakeLimit);
}
else{
$betrayCnt = $general->getVar('betray');
$general->addExperience(-$general->getVar('experience')*0.1*$betrayCnt);
$general->addDedication(-$general->getVar('dedication')*0.1*$betrayCnt);
$general->increaseVarWithLimit('betray', 1, null, GameConst::$maxBetrayCnt);
}
//부대장일 경우
if($general->getVar('troop') == $generalID){
// 모두 탈퇴
$db->update('general', [
'troop'=>0,
], 'troop = %i', $generalID);
$db->delete('troop', 'troop_leader=%i', $generalID);
}
$general->setVar('troop', 0);
if($general->getNPCType() >= 2 && ($env['scenario'] < 100 || Util::randBool(0.01))) {
$str = Util::choiceRandom([
'날 버리다니... 곧 전장에서 복수해주겠다...',
'추방이라... 내가 무얼 잘못했단 말인가...',
'어디 추방해가면서 잘되나 보자... 꼭 복수하겠다...',
'인덕이 제일이거늘... 추방이 웬말인가... 저주한다!',
'날 추방했으니 그 복수로 적국에 정보를 팔아 넘겨야겠군요. 그럼 이만.'
]);
$src = new MessageTarget(
$generalID,
$generalName,
$nationID,
$nation['name'],
$nation['color'],
GetImageURL($general->getVar('imgsvr'), $general->getVar('picture'))
);
$msg = new Message(
Message::MSGTYPE_PUBLIC,
$src,
$src,
$str,
new \DateTime(),
new \DateTime('9999-12-31'),
[]
);
$msg->send();
}
if($env['year'] < $env['startyear']+3) {
//초반엔 군주 부상 증가(엔장 임관지양)
$db->update('general', [
'injury'=>$db->sqleval('least(injury + 1, %i)', 80),
], 'nation=%i AND officer_level=12', $nationID);
$db->update('nation', [
'gennum'=>$db->sqleval('gennum - %i', $general->getNPCType()!=5?1:0),
'gold'=>$db->sqleval('gold + %i', $gold),
'rice'=>$db->sqleval('rice + %i', $rice),
], 'nation = %i', $nationID);
} else {
//이번분기는 추방불가(초반 제외)
$db->update('nation', [
'chief_set'=>$db->sqleval('chief_set | %i', doOfficerSet(0, $myOfficerLevel)),
'gennum'=>$db->sqleval('gennum - %i', $general->getNPCType()!=5?1:0),
'gold'=>$db->sqleval('gold + %i', $gold),
'rice'=>$db->sqleval('rice + %i', $rice),
], 'nation = %i', $nationID);
}
$logger->pushGeneralHistoryLog("<D>{$nation['name']}</>에서 추방됨");
$general->applyDB($db);
return null;
}
if($action == "임명") {
if(2 <= $officerLevel && $officerLevel <= 4){
if(!$destCityID){
Json::die([
'result'=>false,
'reason'=>'도시가 지정되지 않았습니다.'
]);
}
$result = do도시임명($general, $destCityID, $officerLevel);
if($result !== null){
Json::die([
'result'=>false,
'reason'=>$result
]);
}
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
if(5 <= $officerLevel && $officerLevel < 12){
$result = do수뇌임명($general, $officerLevel);
if($result !== null){
Json::die([
'result'=>false,
'reason'=>$result
]);
}
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 지정입니다.'
]);
}
if($action == "추방") {
$result = do추방($general, $myOfficerLevel);
if($result !== null){
Json::die([
'result'=>false,
'reason'=>$result
]);
}
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 명령입니다.'
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$action = Util::getPost('action');
$officerLevel = Util::getPost('officerLevel', 'int');
$destGeneralID = Util::getPost('destGeneralID', 'int');
$destCityID = Util::getPost('destCityID', 'int');
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheValues(['startyear','year','month','scenario']);
$me = $db->queryFirstRow('SELECT no,nation,officer_level from general where owner=%i', $userID);
$myOfficerLevel = $me['officer_level'];
$nationID = $me['nation'];
//수뇌가 아니면 아무것도 할 수 없음
if($myOfficerLevel < 5){
Json::die([
'result'=>false,
'reason'=>'수뇌가 아닙니다.'
]);
}
if($action === '추방' && $destGeneralID==0){
Json::die([
'result'=>false,
'reason'=>'장수가 지정되지 않았습니다.'
]);
}
if($destGeneralID==0){
$general = new DummyGeneral(true);
$general->setVar('nation', $nationID);
}
else{
$general = General::createGeneralObjFromDB($destGeneralID, [
'name', 'leadership', 'strength', 'intel', 'gold','rice',
'troop','officer_level','npc','picture','imgsvr',
'permission','penalty','belong', 'crewtype',
'experience', 'dedication', 'betray', 'dedlevel', 'explevel', 'makelimit',
], 1);
if($general instanceof DummyGeneral){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 장수입니다.'
]);
}
if($nationID != $general->getNationID()){
Json::die([
'result'=>false,
'reason'=>'아국 장수가 아닙니다'
]);
}
}
if($officerLevel == 12){
Json::die([
'result'=>false,
'reason'=>'군주를 대상으로 할 수 없습니다.'
]);
}
function do수뇌임명(General $general, int $targetOfficerLevel):?string{
$generalID = $general->getID();
$nationID = $general->getNationID();
$db = DB::db();
[$chiefSet, $nationLevel] = $db->queryFirstList('SELECT chief_set,level FROM nation WHERE nation = %i',$nationID);
// 임명가능 레벨
$lv = getNationChiefLevel($nationLevel);
if($targetOfficerLevel < $lv){
return '임명불가능한 관직입니다.';
}
if(isOfficerSet($chiefSet, $targetOfficerLevel)){
return '지금은 임명할 수 없습니다.';
}
//기존 장수 일반으로
$db->update('general', [
'officer_level'=>1,
'officer_city'=>0,
], 'nation=%i AND officer_level=%i AND no!=%i', $nationID, $targetOfficerLevel, $generalID);
if($targetOfficerLevel === 11){
}
else if($targetOfficerLevel % 2 == 0){
if($general->getVar('strength') < GameConst::$chiefStatMin){
return '무력이 부족합니다.';
}
}
else{
if($general->getVar('intel') < GameConst::$chiefStatMin){
return '지력이 부족합니다.';
}
}
//신임 장수
$general->setVar('officer_level', $targetOfficerLevel);
$general->setVar('officer_city', 0);
$db->update('nation', [
'chief_set'=> $db->sqleval('chief_set | %i', doOfficerSet(0, $targetOfficerLevel)),
], 'nation=%i', $nationID);
$general->applyDB($db);
return null;
}
function do도시임명(General $general, int $cityID, int $targetOfficerLevel):?string{
$nationID = $general->getNationID();
$db = DB::db();
if(CityConst::byID($cityID) === null){
return '올바르지 않은 도시입니다';
}
$officerSet = $db->queryFirstField('SELECT officer_set FROM city WHERE nation=%i AND city=%i', $nationID, $cityID);
if($officerSet === null){
return '아국 도시가 아닙니다';
}
if(isOfficerSet($officerSet, $targetOfficerLevel)){
return '이미 다른 장수가 임명되어있습니다';
}
//기존 장수 일반으로
$db->update('general', [
'officer_level'=>1,
'officer_city'=>0,
], 'officer_level=%i AND officer_city=%i AND no!=%i', $targetOfficerLevel, $cityID, $general->getID());
if($general instanceof DummyGeneral){
return null;
}
if($targetOfficerLevel === 4 && $general->getVar('strength') < GameConst::$chiefStatMin){
return '무력이 부족합니다.';
}
if($targetOfficerLevel === 3 && $general->getVar('intel') < GameConst::$chiefStatMin){
return '지력이 부족합니다.';
}
//신임 장수
$db->update('city', [
'officer_set'=>$db->sqleval('officer_set | %i', doOfficerSet(0, $targetOfficerLevel)),
], 'city=%i AND nation=%i', $cityID, $nationID);
$general->setVar('officer_level', $targetOfficerLevel);
$general->setVar('officer_city', $cityID);
$general->applyDB($db);
return null;
}
function do추방(General $general, int $myOfficerLevel):?string{
$generalID = $general->getID();
$generalName = $general->getVar('name');
$nationID = $general->getNationID();
//추방할사람이 외교권자이면 불가
$permission = checkSecretPermission($general->getRaw());
if($permission == 4){
return '외교권자는 추방할 수 없습니다.';
}
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$env = $gameStor->getValues(['startyear','year','month','scenario']);
$nation = $db->queryFirstRow('SELECT name,chief_set,color FROM nation WHERE nation=%i', $nationID);
$nationName = $nation['name'];
$logger = $general->getLogger();
//이미 지정했다면 무시
if(isOfficerSet($nation['chief_set'], $myOfficerLevel) || ($myOfficerLevel == 0 && $myOfficerLevel == 12)) {
return '이미 추방 권한을 사용했습니다.';
}
$gold = 0;
$rice = 0;
// 금쌀1000이상은 남김
if($general->getVar('gold') > GameConst::$defaultGold) {
$gold = $general->getVar('gold') - GameConst::$defaultGold;
$general->setVar('gold', GameConst::$defaultGold);
}
if($general->getVar('rice') > GameConst::$defaultRice) {
$rice = $general->getVar('rice') - GameConst::$defaultRice;
$general->setVar('rice', GameConst::$defaultRice);
}
$general->setVar('nation', 0);
$general->setVar('officer_level', 0);
$general->setVar('officer_city', 0);
$general->setVar('belong', 0);
$oldMakeLimit = $general->getVar('makelimit');
$general->setVar('makelimit', 12);
$general->setVar('permission', 'normal');
$josaYi = JosaUtil::pick($generalName, '이');
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <D><b>{$nationName}</b></>에서 <R>추방</>당했습니다.");
$logger->pushGeneralActionLog("<D><b>{$nationName}</b></>에서 <R>추방</>당했습니다.", ActionLogger::PLAIN);
// 명성/공헌 N*10%감소
if($env['year'] <= $env['startyear'] && $general->getNPCType() < 2){
$general->setVar('makelimit', $oldMakeLimit);
}
else{
$betrayCnt = $general->getVar('betray');
$general->addExperience(-$general->getVar('experience')*0.1*$betrayCnt);
$general->addDedication(-$general->getVar('dedication')*0.1*$betrayCnt);
$general->increaseVarWithLimit('betray', 1, null, GameConst::$maxBetrayCnt);
}
//부대장일 경우
if($general->getVar('troop') == $generalID){
// 모두 탈퇴
$db->update('general', [
'troop'=>0,
], 'troop = %i', $generalID);
$db->delete('troop', 'troop_leader=%i', $generalID);
}
$general->setVar('troop', 0);
if($general->getNPCType() >= 2 && ($env['scenario'] < 100 || Util::randBool(0.01))) {
$str = Util::choiceRandom([
'날 버리다니... 곧 전장에서 복수해주겠다...',
'추방이라... 내가 무얼 잘못했단 말인가...',
'어디 추방해가면서 잘되나 보자... 꼭 복수하겠다...',
'인덕이 제일이거늘... 추방이 웬말인가... 저주한다!',
'날 추방했으니 그 복수로 적국에 정보를 팔아 넘겨야겠군요. 그럼 이만.'
]);
$src = new MessageTarget(
$generalID,
$generalName,
$nationID,
$nation['name'],
$nation['color'],
GetImageURL($general->getVar('imgsvr'), $general->getVar('picture'))
);
$msg = new Message(
Message::MSGTYPE_PUBLIC,
$src,
$src,
$str,
new \DateTime(),
new \DateTime('9999-12-31'),
[]
);
$msg->send();
}
if($env['year'] < $env['startyear']+3) {
//초반엔 군주 부상 증가(엔장 임관지양)
$db->update('general', [
'injury'=>$db->sqleval('least(injury + 1, %i)', 80),
], 'nation=%i AND officer_level=12', $nationID);
$db->update('nation', [
'gennum'=>$db->sqleval('gennum - %i', $general->getNPCType()!=5?1:0),
'gold'=>$db->sqleval('gold + %i', $gold),
'rice'=>$db->sqleval('rice + %i', $rice),
], 'nation = %i', $nationID);
} else {
//이번분기는 추방불가(초반 제외)
$db->update('nation', [
'chief_set'=>$db->sqleval('chief_set | %i', doOfficerSet(0, $myOfficerLevel)),
'gennum'=>$db->sqleval('gennum - %i', $general->getNPCType()!=5?1:0),
'gold'=>$db->sqleval('gold + %i', $gold),
'rice'=>$db->sqleval('rice + %i', $rice),
], 'nation = %i', $nationID);
}
$logger->pushGeneralHistoryLog("<D>{$nation['name']}</>에서 추방됨");
$general->applyDB($db);
return null;
}
if($action == "임명") {
if(2 <= $officerLevel && $officerLevel <= 4){
if(!$destCityID){
Json::die([
'result'=>false,
'reason'=>'도시가 지정되지 않았습니다.'
]);
}
$result = do도시임명($general, $destCityID, $officerLevel);
if($result !== null){
Json::die([
'result'=>false,
'reason'=>$result
]);
}
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
if(5 <= $officerLevel && $officerLevel < 12){
$result = do수뇌임명($general, $officerLevel);
if($result !== null){
Json::die([
'result'=>false,
'reason'=>$result
]);
}
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 지정입니다.'
]);
}
if($action == "추방") {
$result = do추방($general, $myOfficerLevel);
if($result !== null){
Json::die([
'result'=>false,
'reason'=>$result
]);
}
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 명령입니다.'
]);
+1 -1
View File
@@ -59,7 +59,7 @@ list(
$npcmode
) = $gameStor->getValuesAsArray(['year', 'month', 'maxgeneral', 'npcmode']);
if(!$npcmode){
if($npcmode!=1){
Json::die([
'result'=>false,
'reason'=>'빙의 가능한 서버가 아닙니다'
+170
View File
@@ -0,0 +1,170 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$pick = Util::getPost('pick');
$leadership = Util::getPost('leadership', 'int', GameConst::$defaultStatMin);
$strength = Util::getPost('leadership', 'int', GameConst::$defaultStatMin);
$intel = Util::getPost('leadership', 'int', GameConst::$defaultStatMin);
$personal = Util::getPost('personal', 'string', null);
$use_own_picture = Util::getPost('use_own_picture', 'bool', false);
if(!$pick){
Json::die([
'result'=>false,
'reason'=>'장수를 선택하지 않았습니다'
]);
}
$session = Session::requireLogin([])->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$rootDB = RootDB::db();
$oNow = new \DateTimeImmutable();
$now = $oNow->format('Y-m-d H:i:s');
$hasGeneralID = $db->queryFirstField('SELECT no FROM general WHERE owner = %i', $userID);
if($hasGeneralID){
Json::die([
'result'=>false,
'reason'=>'이미 장수를 생성했습니다.'
]);
}
$env = $gameStor->getValues(['startyear', 'year', 'month', 'maxgeneral', 'npcmode', 'show_img_level', 'icon_path', 'turnterm', 'turntime']);
$env['fiction'] = false;
$npcmode = $env['npcmode'];
$maxgeneral = $env['maxgeneral'];
if($npcmode!=2){
Json::die([
'result'=>false,
'reason'=>'선택 가능한 서버가 아닙니다'
]);
}
$selectInfo = $db->queryFirstField('SELECT info FROM select_pool WHERE `owner` = %i AND `reserved_until`>=%s AND `unique_name`=%s', $userID, $now, $pick);
if(!$selectInfo){
Json::die([
'result'=>false,
'reason'=>'유효한 장수 목록이 없습니다.'
]);
}
$selectInfo = Json::decode($selectInfo);
$ownerInfo = RootDB::db()->queryFirstRow('SELECT `name`,`picture`,`imgsvr` FROM member WHERE `NO`=%i',$userID);
if(!$ownerInfo){
Json::die([
'result'=>false,
'reason'=>'멤버 정보를 가져오지 못했습니다.'
]);
}
$gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2');
if ($gencount >= $maxgeneral) {
Json::die([
'result'=>false,
'reason'=>'더 이상 등록 할 수 없습니다.'
]);
}
$poolClass = getGeneralPoolClass(GameConst::$targetGeneralPool);
/** @var AbsGeneralPool */
$pickedGeneral = new $poolClass($db, $selectInfo, $now);
$builder = $pickedGeneral->getGeneralBuilder();
foreach(GameConst::$generalPoolAllowOption as $allowOption){
if($allowOption == 'stat'){
$leadership = Util::valueFit($leadership, GameConst::$defaultStatMin, GameConst::$defaultStatMax);
$strength = Util::valueFit($strength, GameConst::$defaultStatMin, GameConst::$defaultStatMax);
$intel = Util::valueFit($intel, GameConst::$defaultStatMin, GameConst::$defaultStatMax);
if($leadership + $strength + $intel > GameConst::$defaultStatTotal){
Json::die([
'result'=>false,
'reason'=>'스탯의 총 합이 올바르지 않습니다.'
]);
}
$builder->setStat($leadership, $strength, $intel);
}
else if($allowOption == 'picture' && $use_own_picture){
$builder->setPicture($ownerInfo['imgsvr'], $ownerInfo['picture']);
}
else if($allowOption == 'ego'){
if(!$personal || $personal == 'Random'){
$personal = Util::choiceRandom(GameConst::$availablePersonality);
}
if(!array_search($personal, GameConst::$availablePersonality)){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 성격입니다.'
]);
}
$builder->setEgo($personal);
}
}
$userNick = $ownerInfo['name'];
$builder->setOwner($userID);
$builder->setOwnerName($userNick);
$builder->setKillturn(5);
$builder->setNPCType(0);
$builder->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $env['turnterm']));
$builder->fillRemainSpecAsZero($env);
$builder->build($env);
$generalID = $builder->getGeneralID();
if(!$generalID){
Json::die([
'result'=>false,
'reason'=>'장수 등록에 실패했습니다.'
]);
}
$pickedGeneral->occupyGeneralName();
$db->update('select_pool',[
'owner'=>null,
'reserved_until'=>null,
], '(owner=%i or reserved_until < %s) AND general_id is NULL', $userID, $now);
$josaYi = JosaUtil::pick($userNick, '이');
$generalName = $builder->getGeneralName();
$josaRo = JosaUtil::pick($generalName, '로');
$cityName = CityConst::byID($builder->getCityID())->name;
$logger = new ActionLogger($generalID, 0, $env['year'], $env['month']);
$logger->pushGeneralHistoryLog("<Y>{$generalName}</>, <G>{$cityName}</>에서 등장");
$logger->pushGlobalActionLog("<G><b>{$cityName}</b></>에서 <Y>{$userNick}</>{$josaYi} <Y>{$generalName}</>{$josaRo} 등장합니다.");
$logger->flush();
pushAdminLog(["가입 : {$userID} // {$session->userName} // {$pick} // ".getenv("REMOTE_ADDR")]);
$rootDB->insert('member_log', [
'member_no' => $userID,
'date'=>TimeUtil::now(),
'action_type'=>'make_general',
'action'=>Json::encode([
'server'=>DB::prefix(),
'type'=>'select',
'generalID'=>$generalID,
'generalName'=>$generalName
])
]);
Json::die([
'result'=>true,
'reason'=>'success'
]);
+6 -5
View File
@@ -43,7 +43,7 @@ $session = Session::requireLogin([
'game'=>null,
'me'=>null
])->setReadOnly();
$userID = Session::getUserID();
$userID = $session->userID;
if(!class_exists('\\sammo\\DB')){
Json::die([
@@ -91,7 +91,8 @@ if(file_exists(__DIR__.'/.htaccess')){
'scenarioName'=>$options['scenarioName'],
'turnterm'=>$options['turnterm'],
'fictionMode'=>($options['fiction']?'가상':'사실'),
'npcMode'=>($options['npcmode']?'가능':'불가'),
'block_general_create'=>(!!$options['block_general_create']),
'npcMode'=>([0=>'불가',1=>'가능',2=>'선택 생성'][$options['npcmode']]),
'openDatetime'=>$reserved['date'],
'starttime'=>$options['starttime'],
'gameConf'=>$options['gameConf'],
@@ -104,7 +105,7 @@ if(file_exists(__DIR__.'/.htaccess')){
//TODO: 천통시에도 예약 오픈 알림이 필요..?
$admin = $gameStor->getValues(['isunited', 'npcmode', 'year', 'month', 'scenario', 'scenario_text', 'maxgeneral', 'turnterm', 'opentime', 'turntime', 'join_mode', 'fiction', 'autorun_user']);
$admin = $gameStor->getValues(['isunited', 'npcmode', 'year', 'month', 'scenario', 'scenario_text', 'maxgeneral', 'turnterm', 'opentime', 'turntime', 'join_mode', 'fiction', 'block_general_create', 'autorun_user']);
$admin['maxUserCnt'] = $admin['maxgeneral'];
$admin['npcMode'] = $admin['npcmode'];
$admin['turnTerm'] = $admin['turnterm'];
@@ -124,8 +125,8 @@ $admin['scenario'] = $admin['scenario_text'];
$admin['userCnt'] = $genCnt;
$admin['npcCnt'] = $npcCnt;
$admin['nationCnt'] = $nationCnt;
$admin['npcMode'] = $admin['npcMode']?'가능':'불가';
$admin['block_general_create'] = !!$admin['block_general_create'];
$admin['npcMode'] = [0=>'불가',1=>'가능',2=>'선택 생성'][$admin['npcMode']];
$admin['fictionMode'] = $admin['fiction']?'가상':'사실';
$otherTextInfo = [];
+2
View File
@@ -8,6 +8,8 @@ WebUtil::requireAJAX();
$session = Session::requireGameLogin([])->setReadOnly();
increaseRefresh("사령턴 입력", 0);
$generalID = $session->generalID;
+2
View File
@@ -8,6 +8,8 @@ WebUtil::requireAJAX();
$session = Session::requireGameLogin([])->setReadOnly();
increaseRefresh("턴 입력", 0);
$generalID = $session->generalID;
$action = Util::getPost('action', 'string');
+82
View File
@@ -0,0 +1,82 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$session = Session::requireGameLogin([])->setReadOnly();
$userID = Session::getUserID();
$generalID = $session->generalID;
increaseRefresh("내정보 수정", 0);
$action = Util::getPost('action');
$tnmt = Util::getPost('tnmt', 'int', 1);
$defence_train = Util::getPost('defence_train', 'int', 80);
$use_treatment = Util::getPost('use_treatment', 'int', 10);
$use_auto_nation_turn = Util::getPost('use_auto_nation_turn', 'int', 1);
//$detachNPC = Util::getPost('detachNPC', 'bool');
$detachNPC = false;
if ($defence_train <= 40) {
$defence_train = 40;
}
if($defence_train <= 90){
$defence_train = Util::round($defence_train, -1);
}
else{
$defence_train = 999;
}
if($tnmt < 0 || $tnmt > 1){
$tnmt = 1;
}
$db = DB::db();
$me = General::createGeneralObjFromDB($generalID);
if($defence_train != $me->getVar('defence_train')){
if($defence_train == 999){
$me->increaseVar('myset', -1);
$me->setVar('defence_train', $defence_train);
$me->increaseVarWithLimit('train', -3, 20);
$me->increaseVarWithLimit('atmos', -3, 20);
}
else{
$me->increaseVar('myset', -1);
$me->setVar('defence_train', $defence_train);
}
}
$me->setAuxVar('use_treatment', Util::valueFit($use_treatment, 10, 100));
if($use_auto_nation_turn != $me->getAuxVar('use_auto_nation_turn')){
$me->setAuxVar('use_auto_nation_turn', $use_auto_nation_turn);
}
if($me->getVar('tnmt') != $tnmt){
$me->setVar('tnmt', $tnmt);
}
if($me->getNPCType() == 1 && $detachNPC){
$turnterm = $gameStor->turnterm;
if($turnterm < 10){
$targetKillTurn = 30 / $turnterm;
}
else{
$targetKillTurn = 60 / $turnterm;
}
$me->setVar('killturn', $targetKillTurn);
}
$me->applyDB($db);
Json::die([
'result'=>true,
'reason'=>'success'
]);
+2 -6
View File
@@ -10,6 +10,7 @@ $session = Session::requireGameLogin([])->setReadOnly();
$userID = Session::getUserID();
$generalID = $session->generalID;
increaseRefresh("NPC 정책 수정", 0);
$type = Util::getPost('type', 'string');
$data = Util::getPost('data', 'string');
@@ -47,12 +48,7 @@ if (!$nationID) {
'reason'=>'국가에 소속되어있지 않습니다.',
]);
}
if ($me['officer_level'] < 5) {
Json::die([
'result'=>false,
'reason'=>'수뇌가 아닙니다.',
]);
}
$permission = checkSecretPermission($me);
if ($permission < 3) {
Json::die([
+467 -449
View File
@@ -1,449 +1,467 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$session = Session::requireLogin([])->setReadOnly();
$userID = Session::getUserID();
$query = Util::getPost('query');
if($query === null){
Json::die([
'result'=>false,
'reason'=>'입력값이 없습니다.'
]);
}
$action = Util::getPost('action');
if($action === null || !in_array($action, ['reorder', 'battle'])){
Json::die([
'result'=>false,
'reason'=>'원하는 동작이 지정되지 않았습니다.'
]);
}
$query = Json::decode($query);
if($query === null){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 JSON입니다.'
]);
}
$defaultCheck = [
'required'=>[
'attackerGeneral', 'attackerCity', 'attackerNation',
'defenderGenerals', 'defenderCity', 'defenderNation',
'year', 'month', 'repeatCnt'
],
'integer'=>[
'year','month','repeatCnt'
],
'between'=>[
['month', [1, 12]]
],
'in'=>[
['repeatCnt', [1, 1000]]
],
'min'=>[
['year', 0]
],
'array'=>[
'attackerGeneral', 'attackerCity', 'attackerNation',
'defenderGenerals', 'defenderCity', 'defenderNation'
],
];
$v = new Validator($query);
$v->rules($defaultCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>$v->errorStr()
]);
}
$year = $query['year'];
$month = $query['month'];
$repeatCnt = $query['repeatCnt'];
$rawAttacker = $query['attackerGeneral'];
$rawAttacker['turntime'] = TimeUtil::now();
$rawAttackerCity = $query['attackerCity'];
$rawAttackerNation = $query['attackerNation'];
$rawDefenderList = $query['defenderGenerals'];
$rawDefenderCity = $query['defenderCity'];
$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',
'explevel', 'experience', 'dedication', 'officer_level', 'officer_city', 'gold', 'rice', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5',
'recent_war'
],
'integer'=>[
'no', 'nation', 'crew', 'crewtype', 'atmos', 'train',
'intel', 'intel_exp', 'strength', 'strength_exp', 'injury', 'leadership', 'leadership_exp',
'explevel', 'experience', 'dedication', 'officer_level', 'officer_city', 'gold', 'rice', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5',
],
'min'=>[
['no', 1],
['nation', 1],
['crew', 0],
['intel', 0],
['strength', 0],
['leadership', 0],
['experience', 0],
['gold', 0],
['rice', 0],
['dex1', 0],
['dex2', 0],
['dex3', 0],
['dex4', 0],
['dex5', 0],
],
'between'=>[
['train', [40, GameConst::$maxTrainByWar]],
['atmos', [40, GameConst::$maxAtmosByWar]],
['explevel', [0, 300]],
['injury', [0, 80]],
['officer_level', [1, 12]]
],
'in'=>[
['personal', array_merge(GameConst::$availablePersonality, GameConst::$optionalPersonality)],
['special2', array_merge(GameConst::$availableSpecialWar, GameConst::$optionalSpecialWar)],
['crewtype', array_keys(GameUnitConst::all())],
['horse', array_merge(array_keys(GameConst::$allItems['horse']), ['None'])],
['weapon', array_merge(array_keys(GameConst::$allItems['weapon']), ['None'])],
['book', array_merge(array_keys(GameConst::$allItems['book']), ['None'])],
['item', array_merge(array_keys(GameConst::$allItems['item']), ['None'])],
]
];
$v = new Validator($rawAttacker);
$v->rules($generalCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[출병자]'.$v->errorStr()
]);
}
$defenderList = [];
foreach($rawDefenderList as $idx=>$rawDefenderGeneral){
$v = new Validator($rawDefenderGeneral);
$v->rules($generalCheck);
if(!$v->validate()){
$idx+=1;
Json::die([
'result'=>false,
'reason'=>"[수비자{$idx}]".$v->errorStr()
]);
}
$defenderList[] = new General($rawDefenderGeneral, null, $rawDefenderCity, $rawAttackerNation, $year, $month, true);
}
$cityCheck = [
'required'=>[
'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',
],
'numeric'=>[
'pop', 'agri', 'comm', 'secu', 'def', 'wall', 'trust', 'dead'
],
'integer'=>[
'city', 'nation', 'supply',
'pop_max', 'agri_max', 'comm_max', 'secu_max', 'def_max', 'wall_max',
'state',
],
'min'=>[
['def', 0],
['wall', 0],
['trust', 0],
['pop', 0],
['comm', 0],
['secu', 0],
['city', 1],
['nation', 0]
],
'in'=>[
['level', array_keys(getCityLevelList())]
]
];
$v = new Validator($rawAttackerCity);
$v->rules($cityCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[출병도시]'.$v->errorStr()
]);
}
$v = new Validator($rawDefenderCity);
$v->rules($cityCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[수비도시]'.$v->errorStr()
]);
}
$nationCheck = [
'required'=>[
'type', 'tech', 'level', 'capital',
'nation', 'name', 'gold', 'rice', 'gennum'
],
'integer'=>[
'level', 'capital', 'nation', 'gennum',
],
'numeric'=>[
'tech', 'gold', 'rice'
],
'min'=>[
['tech', 0],
['gold', 0],
['rice', 0],
['gennum', 1],
],
'in'=>[
['type', GameConst::$availableNationType],
['level', array_keys(getNationLevelList())]
]
];
$v = new Validator($rawAttackerNation);
$v->rules($nationCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[출병국]'.$v->errorStr()
]);
}
$v = new Validator($rawDefenderNation);
$v->rules($nationCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[수비국]'.$v->errorStr()
]);
}
if($action == 'reorder'){
usort($defenderList, function(General $lhs, General $rhs){
return -(extractBattleOrder($lhs) <=> extractBattleOrder($rhs));
});
$order = [];
foreach($defenderList as $defenderGeneral){
$order[] = $defenderGeneral->getID();
}
Json::die([
'result'=>true,
'reason'=>'success',
'order'=>$order
]);
}
usort($defenderList, function(General $lhs, General $rhs){
return -(extractBattleOrder($lhs) <=> extractBattleOrder($rhs));
});
$rawDefenderList = array_map(function(General $general){
return $general->getRaw();
}, $defenderList);
unset($defenderList);
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$startYear = $gameStor->startyear;
$cityRate = Util::round(($year - $startYear) / 1.5) + 60;
function simulateBattle(
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
$startYear, $year, $month, $cityRate
){
$attacker = new WarUnitGeneral(
new General($rawAttacker, null, $rawAttackerCity, $rawAttackerNation, $year, $month),
$rawAttackerNation,
true
);
$city = new WarUnitCity($rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate);
$iterDefender = new \ArrayIterator($rawDefenderList);
$iterDefender->rewind();
$battleResult = [];
$attackerRice = $rawAttacker['rice'];
$defenderRice = 0;
$getNextDefender = function(?WarUnit $prevDefender, bool $reqNext)
use ($iterDefender, $rawDefenderCity, $rawDefenderNation, $year, $month, &$battleResult, &$defenderRice) {
if($prevDefender !== null){
$prevDefender->getLogger()->rollback();
$battleResult[] = $prevDefender;
if($prevDefender instanceof WarUnitGeneral){
$defenderRice -= $prevDefender->getVar('rice');
}
}
if(!$reqNext){
return null;
}
if(!$iterDefender->valid()){
return null;
}
$defenderObj = new General($iterDefender->current(), null, $rawDefenderCity, $rawDefenderNation, $year, $month);
if(extractBattleOrder($defenderObj) <= 0){
return null;
}
$defenderRice += $defenderObj->getVar('rice');
$retVal = new WarUnitGeneral(
$defenderObj,
$rawDefenderNation,
false
);
$iterDefender->next();
return $retVal;
};
$conquerCity = processWar_NG($attacker, $getNextDefender, $city, $year - $startYear);
$rawDefenderCity = $city->getRaw();
$updateAttackerNation = [];
$updateDefenderNation = [];
$attackerRice -= $attacker->getVar('rice');
if($city->getPhase() > 0){
$rice = $city->getKilled() / 100 * 0.8;
$rice *= $city->getCrewType()->rice;
$rice *= getTechCost($rawDefenderNation['tech']);
$rice *= $cityRate / 100 - 0.2;
Util::setRound($rice);
$defenderRice += $rice;
}
$totalDead = $attacker->getKilled() + $attacker->getDead();
$attackerCityDead = $totalDead * 0.4;
$defenderCityDead = $totalDead * 0.6;
return [$attacker, $city, $battleResult, $conquerCity, $attackerRice, $defenderRice];
}
$lastWarLog = [];
$attackerKilled = 0;
$attackerDead = 0;
$attackerMaxKilled = 0;
$attackerMinKilled = PHP_INT_MAX;
$attackerMaxDead = 0;
$attackerMinDead = PHP_INT_MAX;
$attackerAvgRice = 0;
$defenderAvgRice = 0;
$avgPhase = 0;
$avgWar = 0;
$attackerActivatedSkills = [];
$defendersActivatedSkills = [];
foreach(Util::range($repeatCnt) as $repeatIdx){
/** @var WarUnit $attacker */
[$attacker, $city, $battleResult, $conquerCity, $attackerRice, $defenderRice] = simulateBattle(
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
$startYear, $year, $month, $cityRate
);
$lastWarLog = Util::mapWithKey(function($key, $values){
return ConvertLog(join('<br>', $values));
}, $attacker->getLogger()->rollback());
$avgPhase += $attacker->getPhase() / $repeatCnt;
$killed = $attacker->getKilled();
$dead = $attacker->getDead();
$attackerKilled += $killed / $repeatCnt;
$attackerDead += $dead / $repeatCnt;
$attackerMaxKilled = max($attackerMaxKilled, $killed);
$attackerMinKilled = min($attackerMinKilled, $killed);
$attackerMaxDead = max($attackerMaxDead, $dead);
$attackerMinDead = min($attackerMinDead, $dead);
$attackerAvgRice += $attackerRice / $repeatCnt;
$defenderAvgRice += $defenderRice / $repeatCnt;
$avgWar += count($battleResult) / $repeatCnt;
foreach($attacker->getActivatedSkillLog() as $skillName => $skillCnt){
if(!key_exists($skillName, $attackerActivatedSkills)){
$attackerActivatedSkills[$skillName] = $skillCnt / $repeatCnt;
}
else{
$attackerActivatedSkills[$skillName] += $skillCnt / $repeatCnt;
}
}
foreach($battleResult as $idx=>$defender){
while($idx >= count($defendersActivatedSkills)){
$defendersActivatedSkills[] = [];
}
$activatedSkills = &$defendersActivatedSkills[$idx];
foreach($defender->getActivatedSkillLog() as $skillName => $skillCnt){
if(!key_exists($skillName, $activatedSkills)){
$activatedSkills[$skillName] = $skillCnt / $repeatCnt;
}
else{
$activatedSkills[$skillName] += $skillCnt / $repeatCnt;
}
}
}
}
Json::die([
'result'=>true,
'datetime'=>$rawAttacker['turntime'],
'reason'=>'success',
'lastWarLog'=>$lastWarLog,
'avgWar'=>$avgWar,
'phase'=>$avgPhase,
'killed'=>$attackerKilled,
'maxKilled'=>$attackerMaxKilled,
'minKilled'=>$attackerMinKilled,
'dead'=>$attackerDead,
'maxDead'=>$attackerMaxDead,
'minDead'=>$attackerMinDead,
'attackerRice'=>$attackerAvgRice,
'defenderRice'=>$defenderAvgRice,
'attackerSkills'=>$attackerActivatedSkills,
'defendersSkills'=>$defendersActivatedSkills,
]);
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$session = Session::requireLogin([])->setReadOnly();
$userID = Session::getUserID();
increaseRefresh("시뮬레이터", 0);
$query = Util::getPost('query');
if($query === null){
Json::die([
'result'=>false,
'reason'=>'입력값이 없습니다.'
]);
}
$action = Util::getPost('action');
if($action === null || !in_array($action, ['reorder', 'battle'])){
Json::die([
'result'=>false,
'reason'=>'원하는 동작이 지정되지 않았습니다.'
]);
}
$query = Json::decode($query);
if($query === null){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 JSON입니다.'
]);
}
$defaultCheck = [
'required'=>[
'attackerGeneral', 'attackerCity', 'attackerNation',
'defenderGenerals', 'defenderCity', 'defenderNation',
'year', 'month', 'repeatCnt'
],
'integer'=>[
'year','month','repeatCnt'
],
'between'=>[
['month', [1, 12]]
],
'in'=>[
['repeatCnt', [1, 1000]]
],
'min'=>[
['year', 0]
],
'array'=>[
'attackerGeneral', 'attackerCity', 'attackerNation',
'defenderGenerals', 'defenderCity', 'defenderNation'
],
];
$v = new Validator($query);
$v->rules($defaultCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>$v->errorStr()
]);
}
$year = $query['year'];
$month = $query['month'];
$repeatCnt = $query['repeatCnt'];
$rawAttacker = $query['attackerGeneral'];
$rawAttacker['turntime'] = TimeUtil::now();
$rawAttackerCity = $query['attackerCity'];
$rawAttackerNation = $query['attackerNation'];
$rawDefenderList = $query['defenderGenerals'];
$rawDefenderCity = $query['defenderCity'];
$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',
'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',
'explevel', 'experience', 'dedication', 'officer_level', 'officer_city', 'gold', 'rice', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5',
'warnum', 'killnum', 'killcrew',
],
'min'=>[
['no', 1],
['nation', 1],
['crew', 0],
['intel', 0],
['strength', 0],
['leadership', 0],
['experience', 0],
['gold', 0],
['rice', 0],
['dex1', 0],
['dex2', 0],
['dex3', 0],
['dex4', 0],
['dex5', 0],
['warnum', 0],
['killnum', 0],
['killcrew', 0],
],
'between'=>[
['train', [40, GameConst::$maxTrainByWar]],
['atmos', [40, GameConst::$maxAtmosByWar]],
['explevel', [0, 300]],
['injury', [0, 80]],
['officer_level', [1, 12]]
],
'in'=>[
['personal', array_merge(GameConst::$availablePersonality, GameConst::$optionalPersonality)],
['special2', array_merge(GameConst::$availableSpecialWar, GameConst::$optionalSpecialWar)],
['crewtype', array_keys(GameUnitConst::all())],
['horse', array_merge(array_keys(GameConst::$allItems['horse']), ['None'])],
['weapon', array_merge(array_keys(GameConst::$allItems['weapon']), ['None'])],
['book', array_merge(array_keys(GameConst::$allItems['book']), ['None'])],
['item', array_merge(array_keys(GameConst::$allItems['item']), ['None'])],
]
];
$v = new Validator($rawAttacker);
$v->rules($generalCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[출병자]'.$v->errorStr()
]);
}
$rawAttacker['owner'] = 0;
$defenderList = [];
foreach($rawDefenderList as $idx=>$rawDefenderGeneral){
$v = new Validator($rawDefenderGeneral);
$v->rules($generalCheck);
if(!$v->validate()){
$idx+=1;
Json::die([
'result'=>false,
'reason'=>"[수비자{$idx}]".$v->errorStr()
]);
}
$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',
'trust', 'level',
'pop_max', 'agri_max', 'comm_max', 'secu_max', 'def_max', 'wall_max',
'dead', 'state', 'conflict',
],
'numeric'=>[
'pop', 'agri', 'comm', 'secu', 'def', 'wall', 'trust', 'dead'
],
'integer'=>[
'city', 'nation', 'supply',
'pop_max', 'agri_max', 'comm_max', 'secu_max', 'def_max', 'wall_max',
'state',
],
'min'=>[
['def', 0],
['wall', 0],
['trust', 0],
['pop', 0],
['comm', 0],
['secu', 0],
['city', 1],
['nation', 0]
],
'in'=>[
['level', array_keys(getCityLevelList())]
]
];
$v = new Validator($rawAttackerCity);
$v->rules($cityCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[출병도시]'.$v->errorStr()
]);
}
$v = new Validator($rawDefenderCity);
$v->rules($cityCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[수비도시]'.$v->errorStr()
]);
}
$nationCheck = [
'required'=>[
'type', 'tech', 'level', 'capital',
'nation', 'name', 'gold', 'rice', 'gennum'
],
'integer'=>[
'level', 'capital', 'nation', 'gennum',
],
'numeric'=>[
'tech', 'gold', 'rice'
],
'min'=>[
['tech', 0],
['gold', 0],
['rice', 0],
['gennum', 1],
],
'in'=>[
['type', GameConst::$availableNationType],
['level', array_keys(getNationLevelList())]
]
];
$v = new Validator($rawAttackerNation);
$v->rules($nationCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[출병국]'.$v->errorStr()
]);
}
$v = new Validator($rawDefenderNation);
$v->rules($nationCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[수비국]'.$v->errorStr()
]);
}
if($action == 'reorder'){
usort($defenderList, function(General $lhs, General $rhs){
return -(extractBattleOrder($lhs) <=> extractBattleOrder($rhs));
});
$order = [];
foreach($defenderList as $defenderGeneral){
$order[] = $defenderGeneral->getID();
}
Json::die([
'result'=>true,
'reason'=>'success',
'order'=>$order
]);
}
usort($defenderList, function(General $lhs, General $rhs){
return -(extractBattleOrder($lhs) <=> extractBattleOrder($rhs));
});
$rawDefenderList = array_map(function(General $general){
return $general->getRaw();
}, $defenderList);
unset($defenderList);
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$startYear = $gameStor->startyear;
$cityRate = Util::round(($year - $startYear) / 1.5) + 60;
function extractRankVar(array $rawVal):array{
$rankVars = [];
foreach($rawVal as $rawKey=>$rawVal){
if(key_exists($rawKey, General::RANK_COLUMN)){
$rankVars[$rawKey] = $rawVal;
}
}
return $rankVars;
}
function simulateBattle(
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
$startYear, $year, $month, $cityRate
){
$attacker = new WarUnitGeneral(
new General($rawAttacker, extractRankVar($rawAttacker), $rawAttackerCity, $rawAttackerNation, $year, $month),
$rawAttackerNation,
true
);
$city = new WarUnitCity($rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate);
$iterDefender = new \ArrayIterator($rawDefenderList);
$iterDefender->rewind();
$battleResult = [];
$attackerRice = $rawAttacker['rice'];
$defenderRice = 0;
$getNextDefender = function(?WarUnit $prevDefender, bool $reqNext)
use ($iterDefender, $rawDefenderCity, $rawDefenderNation, $year, $month, &$battleResult, &$defenderRice) {
if($prevDefender !== null){
$prevDefender->getLogger()->rollback();
$battleResult[] = $prevDefender;
if($prevDefender instanceof WarUnitGeneral){
$defenderRice -= $prevDefender->getVar('rice');
}
}
if(!$reqNext){
return null;
}
if(!$iterDefender->valid()){
return null;
}
$defenderObj = new General($iterDefender->current(), extractRankVar($iterDefender->current()), $rawDefenderCity, $rawDefenderNation, $year, $month);
if(extractBattleOrder($defenderObj) <= 0){
return null;
}
$defenderRice += $defenderObj->getVar('rice');
$retVal = new WarUnitGeneral(
$defenderObj,
$rawDefenderNation,
false
);
$iterDefender->next();
return $retVal;
};
$conquerCity = processWar_NG($attacker, $getNextDefender, $city, $year - $startYear);
$rawDefenderCity = $city->getRaw();
$updateAttackerNation = [];
$updateDefenderNation = [];
$attackerRice -= $attacker->getVar('rice');
if($city->getPhase() > 0){
$rice = $city->getKilled() / 100 * 0.8;
$rice *= $city->getCrewType()->rice;
$rice *= getTechCost($rawDefenderNation['tech']);
$rice *= $cityRate / 100 - 0.2;
Util::setRound($rice);
$defenderRice += $rice;
}
$totalDead = $attacker->getKilled() + $attacker->getDead();
$attackerCityDead = $totalDead * 0.4;
$defenderCityDead = $totalDead * 0.6;
return [$attacker, $city, $battleResult, $conquerCity, $attackerRice, $defenderRice];
}
$lastWarLog = [];
$attackerKilled = 0;
$attackerDead = 0;
$attackerMaxKilled = 0;
$attackerMinKilled = PHP_INT_MAX;
$attackerMaxDead = 0;
$attackerMinDead = PHP_INT_MAX;
$attackerAvgRice = 0;
$defenderAvgRice = 0;
$avgPhase = 0;
$avgWar = 0;
$attackerActivatedSkills = [];
$defendersActivatedSkills = [];
foreach(Util::range($repeatCnt) as $repeatIdx){
/** @var WarUnit $attacker */
[$attacker, $city, $battleResult, $conquerCity, $attackerRice, $defenderRice] = simulateBattle(
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
$startYear, $year, $month, $cityRate
);
$lastWarLog = Util::mapWithKey(function($key, $values){
return ConvertLog(join('<br>', $values));
}, $attacker->getLogger()->rollback());
$avgPhase += $attacker->getPhase() / $repeatCnt;
$killed = $attacker->getKilled();
$dead = $attacker->getDead();
$attackerKilled += $killed / $repeatCnt;
$attackerDead += $dead / $repeatCnt;
$attackerMaxKilled = max($attackerMaxKilled, $killed);
$attackerMinKilled = min($attackerMinKilled, $killed);
$attackerMaxDead = max($attackerMaxDead, $dead);
$attackerMinDead = min($attackerMinDead, $dead);
$attackerAvgRice += $attackerRice / $repeatCnt;
$defenderAvgRice += $defenderRice / $repeatCnt;
$avgWar += count($battleResult) / $repeatCnt;
foreach($attacker->getActivatedSkillLog() as $skillName => $skillCnt){
if(!key_exists($skillName, $attackerActivatedSkills)){
$attackerActivatedSkills[$skillName] = $skillCnt / $repeatCnt;
}
else{
$attackerActivatedSkills[$skillName] += $skillCnt / $repeatCnt;
}
}
foreach($battleResult as $idx=>$defender){
while($idx >= count($defendersActivatedSkills)){
$defendersActivatedSkills[] = [];
}
$activatedSkills = &$defendersActivatedSkills[$idx];
foreach($defender->getActivatedSkillLog() as $skillName => $skillCnt){
if(!key_exists($skillName, $activatedSkills)){
$activatedSkills[$skillName] = $skillCnt / $repeatCnt;
}
else{
$activatedSkills[$skillName] += $skillCnt / $repeatCnt;
}
}
}
}
Json::die([
'result'=>true,
'datetime'=>$rawAttacker['turntime'],
'reason'=>'success',
'lastWarLog'=>$lastWarLog,
'avgWar'=>$avgWar,
'phase'=>$avgPhase,
'killed'=>$attackerKilled,
'maxKilled'=>$attackerMaxKilled,
'minKilled'=>$attackerMinKilled,
'dead'=>$attackerDead,
'maxDead'=>$attackerMaxDead,
'minDead'=>$attackerMinDead,
'attackerRice'=>$attackerAvgRice,
'defenderRice'=>$defenderAvgRice,
'attackerSkills'=>$attackerActivatedSkills,
'defendersSkills'=>$defendersActivatedSkills,
]);
+2
View File
@@ -15,6 +15,8 @@ $troop = Util::getPost('troop', 'int');
$session = Session::requireGameLogin([])->setReadOnly();
$userID = $session::getUserID();
increaseRefresh("부대명령", 0);
$db = DB::db();
$me = $db->queryFirstRow('SELECT `no`, name, nation, troop FROM general WHERE `owner`=%i', $userID);
+151
View File
@@ -0,0 +1,151 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$pick = Util::getPost('pick');
if(!$pick){
Json::die([
'result'=>false,
'reason'=>'장수를 선택하지 않았습니다'
]);
}
$session = Session::requireLogin([])->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$rootDB = RootDB::db();
$oNow = new \DateTimeImmutable();
$now = $oNow->format('Y-m-d H:i:s');
$generalID = $db->queryFirstField('SELECT no FROM general WHERE owner = %i', $userID);
if(!$generalID){
Json::die([
'result'=>false,
'reason'=>'장수가 생성하지 않았습니다. 이미 사망하지 않았는지 확인해보세요.'
]);
}
list(
$year,
$month,
$maxgeneral,
$npcmode,
$turnterm
) = $gameStor->getValuesAsArray(['year', 'month', 'maxgeneral', 'npcmode', 'turnterm']);
if($npcmode!=2){
Json::die([
'result'=>false,
'reason'=>'선택 가능한 서버가 아닙니다'
]);
}
$info = $db->queryFirstField('SELECT info FROM select_pool WHERE `owner` = %i AND `reserved_until`>=%s AND `unique_name`=%s', $userID, $now, $pick);
if(!$info){
Json::die([
'result'=>false,
'reason'=>'유효한 장수 목록이 없습니다.'
]);
}
$ownerInfo = RootDB::db()->queryFirstRow('SELECT `name`,`picture`,`imgsvr` FROM member WHERE `NO`=%i',$userID);
if(!$ownerInfo){
Json::die([
'result'=>false,
'reason'=>'멤버 정보를 가져오지 못했습니다.'
]);
}
$info = Json::decode($info);
$generalObj = General::createGeneralObjFromDB($generalID);
$oldGeneralName = $generalObj->getName();
$db->update('select_pool', [
'general_id'=>-$generalID,
'owner'=>null,
'reserved_until'=>null
], 'unique_name=%s AND `reserved_until` IS NOT NULL AND owner = %i', $info['uniqueName'], $userID);
if($db->affectedRows()==0){
Json::die([
'result'=>false,
'reason'=>'동시성 제어에 문제가 발생했습니다. 버그 제보를 부탁드립니다.'
]);
}
$db->update('select_pool', [
'general_id'=>null,
'owner'=>null,
'reserved_until'=>null,
], 'unique_name != %s AND general_id = %i', $info['uniqueName'], $generalID);
$db->update('select_pool', [
'general_id'=>$generalID,
], 'general_id=%i', -$generalID);
if($db->affectedRows()==0){
Json::die([
'result'=>false,
'reason'=>'장수 선택 과정에 문제가 발생했습니다.. 버그 제보를 부탁드립니다.'
]);
}
$db->update('select_pool',[
'owner'=>null,
'reserved_until'=>null,
], '(owner=%i or reserved_until < %s) AND general_id is NULL', $userID, $now);
if(key_exists('leadership', $info)){
$generalObj->updateVar('leadership', $info['leadership']);
$generalObj->updateVar('strength', $info['strength']);
$generalObj->updateVar('intel', $info['intel']);
}
if(key_exists('picture', $info)){
$generalObj->updateVar('imgsvr', $info['imgsvr']);
$generalObj->updateVar('picture', $info['picture']);
}
if(key_exists('generalName', $info)){
$generalObj->updateVar('name', $info['generalName']);
}
if(key_exists('dex', $info)){
$generalObj->updateVar('dex1', $info['dex'][0]);
$generalObj->updateVar('dex2', $info['dex'][1]);
$generalObj->updateVar('dex3', $info['dex'][2]);
$generalObj->updateVar('dex4', $info['dex'][3]);
$generalObj->updateVar('dex5', $info['dex'][4]);
}
if(key_exists('ego', $info)){
$generalObj->updateVar('personal', $info['ego']);
}
if(key_exists('specialDomestic', $info)){
$generalObj->updateVar('special', $info['specialDomestic']);
}
if(key_exists('specialWar', $info)){
$generalObj->updateVar('special2', $info['specialWar']);
}
$generalObj->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $turnterm));
$userNick = $ownerInfo['name'];
$generalObj->setVar('owner_name', $userNick);
$josaYi = JosaUtil::pick($userNick, '이');
$generalName = $info['generalName'];
$josaRo = JosaUtil::pick($generalName, '로');
$logger = $generalObj->getLogger();
$logger->pushGeneralHistoryLog("장수를 <Y>{$oldGeneralName}</>에서 <Y>{$generalName}</>{$josaRo} 변경");
$logger->pushGlobalActionLog("<Y>{$userNick}</>{$josaYi} 장수를 <Y>{$oldGeneralName}</>에서 <Y>{$generalName}</>{$josaRo} 변경합니다.");
$generalObj->applyDB($db);
Json::die([
'result'=>true,
'reason'=>'success'
]);
+8 -2
View File
@@ -13,7 +13,10 @@ $gameStor = KVStorage::getStorage($db, 'game_env');
$autorun_user = $gameStor->autorun_user;
if($autorun_user['limit_minutes']??false){
//자동 턴인 경우에는 휴가 불가
header('location:b_myPage.php', true, 303);
Json::die([
'result'=>false,
'reason'=>'자동 턴인 경우에는 휴가 명령이 불가능합니다.'
]);
}
$killturn = $gameStor->killturn;
@@ -23,5 +26,8 @@ $db->update('general', [
], 'owner=%i', $userID);
header('location:b_myPage.php', true, 303);
Json::die([
'result'=>true,
'reason'=>'success'
]);
+6 -2
View File
@@ -24,7 +24,12 @@ if (!$member) {
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['block_general_create','show_img_level','maxgeneral']);
if($admin['block_general_create']){
MessageBox("잘못된 접근입니다!!!");
echo "<script>history.go(-1);</script>";
exit(1);
}
?>
<!DOCTYPE html>
<html>
@@ -66,7 +71,6 @@ echo Json::encode((object)$charInfoText);
<tr><td align=center><?=info(0)?></td></tr>
</table>
<?php
$admin = $gameStor->getValues(['show_img_level','maxgeneral']);
$gencount = $db->queryFirstField('SELECT count(no) FROM general WHERE npc<2');
+5 -3
View File
@@ -169,7 +169,7 @@ if ($genius) {
'dex5'=>0
]);
} else {
$specage2 = Util::valueFit(Util::round((GameConst::$retirementYear - $age)/4 - $relYear / 2), 3) + $age;
$specage2 = Util::valueFit(Util::round((GameConst::$retirementYear - $age)/6 - $relYear / 2), 3) + $age;
$special2 = GameConst::$defaultSpecialWar;
}
//내특
@@ -185,10 +185,10 @@ if($relYear < 3){
$experience = 0;
}
else{
$expGenCount = $db->queryFirstField('SELECT count(*) FROM general WHERE nation != 0 AND npc < 5');
$expGenCount = $db->queryFirstField('SELECT count(*) FROM general WHERE nation != 0 AND npc < 4');
$targetGenOrder = Util::round($expGenCount * 0.2);
$experience = $db->queryFirstField(
'SELECT experience FROM general WHERE nation != 0 AND npc < 5 ORDER BY experience ASC LIMIT %i, 1',
'SELECT experience FROM general WHERE nation != 0 AND npc < 4 ORDER BY experience ASC LIMIT %i, 1',
$targetGenOrder - 1
);
$experience *= 0.8;
@@ -266,6 +266,8 @@ foreach(Util::range(GameConst::$maxTurn) as $turnIdx){
}
$db->insert('general_turn', $turnRows);
resetInheritanceUser($userID);
$rank_data = [];
foreach(array_keys(General::RANK_COLUMN) as $rankColumn){
$rank_data[] = [
+931 -799
View File
@@ -1,800 +1,932 @@
jQuery(function($){
var $generalForm = $('.form_sample .general_detail');
var $defenderHeaderForm = $('.form_sample .card-header');
var $defenderColumn = $('.defender-column');
var defenderNoList = {};
var $attackerCard = $('.attacker_form');
var initBasicEvent = function(){
$('.form_injury').change(function(){
var $this = $(this);
var $general = getGeneralDetail($this);
var $helptext = $general.find('.injury_helptext');
var injury = parseInt($this.val());
//FIXME: PHP 코드와 항상 일치하도록 변경
var text = '건강';
var color = 'white';
if(injury > 60){
text = '위독';
color = 'red';
}
else if(injury > 40){
text = '심각';
color = 'magenta';
}
else if(injury > 20){
text = '중상';
color = 'orange';
}
else if(injury > 0){
text = '경상';
color = 'yellow';
}
$helptext.html(text).css('color', color);
});
$('.export_general').click(function(){
var $btn = $(this);
var $general = getGeneralDetail($btn);
var values = exportGeneralInfo($general);
console.log(values);
});
$('.delete-defender').click(function(){
var $card = getGeneralFrame($(this));
deleteDefender($card);
});
$('.copy-defender').click(function(){
var $card = getGeneralFrame($(this));
copyDefender($card);
});
$('.add-defender').click(function(){
addDefender();
});
$('.btn-general-load').click(function(){
var $file = $(this).prev();
$file[0].click();
})
$('.form_load_general_file').on('change', function(e){
e.preventDefault();
var $this = $(this);
var $card = getGeneralFrame($this);
var files = e.target.files;
importGeneralInfoByFile(files, $card);
return false;
});
$('.btn-general-save').click(function(){
var $this = $(this);
var $general = getGeneralDetail($this);
var generalData = exportGeneralInfo($general);
var filename = "general_{0}.json".format(generalData.name);
var saveData = JSON.stringify({
objType:'general',
data:generalData
}, null, 4);
download(saveData, filename, 'application/json');
});
$('.btn-battle-load').click(function(){
var $file = $(this).prev();
$file[0].click();
})
$('.form_load_battle_file').on('change', function(e){
e.preventDefault();
var $this = $(this);
var files = e.target.files;
importBattleInfoByFile(files);
return false;
});
$('.btn-battle-save').click(function(){
var battleData = exportAllData();
var filename = "battle_{0}.json".format(moment().format('YYYYMMDD_hhmmss'));
var saveData = JSON.stringify({
objType:'battle',
data:battleData
}, null, 4);
download(saveData, filename, 'application/json');
})
var $generals = $('.general_detail');
$generals.bind('dragover dragleave', function(e) {
e.stopPropagation()
e.preventDefault()
})
$generals.bind('drop', function(e){
e.preventDefault();
var $this = $(this);
var $card = getGeneralFrame($this);
var files = e.originalEvent.dataTransfer.files;
importGeneralInfoByFile(files, $card);
return false;
});
var $battlePad = $('.dragpad_battle');
$battlePad.bind('dragover dragleave', function(e) {
e.stopPropagation()
e.preventDefault()
})
$battlePad.bind('drop', function(e){
e.preventDefault();
var files = e.originalEvent.dataTransfer.files;
importBattleInfoByFile(files);
return false;
});
}
var importGeneralInfo = function($general, data){
var setVal = function(query, val){
$general.find(query).val(val).change();
}
setVal('.form_general_name', data.name);
setVal('.form_officer_level', data.officer_level);
setVal('.form_exp_level', data.explevel);
setVal('.form_injury', data.injury);
setVal('.form_leadership', data.leadership);
setVal('.form_general_horse', data.horse);
setVal('.form_strength', data.strength);
setVal('.form_general_weap', data.weapon);
setVal('.form_intel', data.intel);
setVal('.form_general_book', data.book);
setVal('.form_general_item', data.item);
setVal('.form_injury', data.injury);
setVal('.form_rice', data.rice);
setVal('.form_general_character', data.personal);
setVal('.form_general_special_war', data.special2);
setVal('.form_crew', data.crew);
setVal('.form_crewtype', data.crewtype);
setVal('.form_atmos', data.atmos);
setVal('.form_train', data.train);
setVal('.form_dex1', data.dex1);
setVal('.form_dex2', data.dex2);
setVal('.form_dex3', data.dex3);
setVal('.form_dex4', data.dex4);
setVal('.form_dex5', data.dex5);
setVal('.form_defence_train', data.defence_train);
if(!setGeneralNo($general, data.no)){
setGeneralNo($general, generateNewGeneralNo());
}
}
var exportGeneralInfo = function($general){
var getInt = function(query){
return parseInt($general.find(query).val());
}
var getVal = function(query){
return $general.find(query).val();
}
return {
no:getGeneralNo($general),
name:getVal('.form_general_name'),
officer_level:getInt('.form_officer_level'),
explevel:getInt('.form_exp_level'),
leadership:getInt('.form_leadership'),
horse:getVal('.form_general_horse'),
strength:getInt('.form_strength'),
weapon:getVal('.form_general_weap'),
intel:getInt('.form_intel'),
book:getVal('.form_general_book'),
item:getVal('.form_general_item'),
injury:getInt('.form_injury'),
rice:getInt('.form_rice'),
personal:getVal('.form_general_character'),
special2:getVal('.form_general_special_war'),
crew:getInt('.form_crew'),
crewtype:getInt('.form_crewtype'),
atmos:getInt('.form_atmos'),
train:getInt('.form_train'),
dex1:getInt('.form_dex1'),
dex2:getInt('.form_dex2'),
dex3:getInt('.form_dex3'),
dex4:getInt('.form_dex4'),
dex5:getInt('.form_dex5'),
defence_train:getInt('.form_defence_train'),
};
}
var importBattleInfoByFile = function(files){
if(files === null){
alert('파일 에러!');
return false;
}
if(files.length < 1){
alert("파일 에러!");
return false;
}
var file = files[0];
if(file.size > 1024*1024){
alert('파일이 너무 큽니다!');
return false;
}
if(file.type === ''){
alert('폴더를 업로드할 수 없습니다!');
return false;
}
var reader = new FileReader();
reader.onload = function(){
var battleData = {};
try {
battleData = JSON.parse(reader.result);
} catch(e) {
alert('올바르지 않은 파일 형식입니다');
return false;
}
if(!('objType' in battleData)){
alert('파일 형식을 확인할 수 없습니다');
return false;
}
if(battleData.objType != 'battle'){
alert('전투 데이터가 아닙니다');
return false;
}
importBattleInfo(battleData.data);
return true;
};
try {
reader.readAsText(file);
}
catch(e) {
alert('파일을 읽는데 실패했습니다.');
return false;
}
return true;
}
var importGeneralInfoByFile = function(files, $card){
if($card === undefined){
$card = addDefender();
}
if(files === null){
alert('파일 에러!');
return false;
}
if(files.length < 1){
alert("파일 에러!");
return false;
}
var file = files[0];
if(file.size > 1024*1024){
alert('파일이 너무 큽니다!');
return false;
}
if(file.type === ''){
alert('폴더를 업로드할 수 없습니다!');
return false;
}
var reader = new FileReader();
reader.onload = function(){
var generalData = {};
try {
generalData = JSON.parse(reader.result);
} catch(e) {
alert('올바르지 않은 파일 형식입니다');
return false;
}
if(!('objType' in generalData)){
alert('파일 형식을 확인할 수 없습니다');
return false;
}
if(generalData.objType == 'battle'){
importBattleInfo(generalData.data);
return true;
}
if(generalData.objType != 'general'){
alert('장수 데이터가 아닙니다');
return false;
}
$card.find('.form_load_general_file').val('');
importGeneralInfo($card, generalData.data);
return true;
};
try {
reader.readAsText(file);
}
catch(e) {
alert('파일을 읽는데 실패했습니다.');
return false;
}
return true;
}
var extendGeneralInfoForDB = function(generalData){
var dbVal = {
nation: (generalData.no)<=1 ? 1 : 2,
city: (generalData.no)<=1 ? 1 : 3,
turntime:'2018-08-26 12:00',
special:defaultSpecialDomestic,
leadership_exp:0,
strength_exp:0,
intel_exp:0,
gold:10000,
dedication:0,
recent_war:'2018-08-26 12:00',
experience:Math.pow(generalData.explevel, 2),
};
return $.extend({}, generalData, dbVal);
}
var getGeneralFrame = function($btn){
var $card = $btn.closest('.general_form');
return $card;
}
var getGeneralDetail = function($btn){
var $card = getGeneralFrame($btn);
var $general = $card.find('.general_detail');
return $general;
}
var getGeneralNo = function($btn){
return parseInt(getGeneralFrame($btn).data('general_no'));
}
var setGeneralNo = function($btn, value){
if(value == 1){
//1번은 무조건 공격자임
return false;
}
if(value in defenderNoList){
return false;
}
var $card = getGeneralFrame($btn);
$card.data('general_no', value);
defenderNoList[value] = $card;
return true;
}
var generateNewGeneralNo = function(){
while(true){
var newGeneralNo = parseInt(Math.random()*(1<<24))+2;
if(newGeneralNo in defenderNoList){
continue;
}
return newGeneralNo;
}
}
var deleteGeneralNo = function($btn){
var $card = getGeneralFrame($btn);
$card.removeData('general_no');
var generalNo = getGeneralNo($card);
delete defenderNoList[generalNo];
}
var addDefender = function($cardAfter){
var $newCard = $('<div class="card mb-2 defender_form general_form"></div>');
if($cardAfter === undefined){
$defenderColumn.append($newCard);
}
else{
$cardAfter.after($newCard);
}
$newCard.append($defenderHeaderForm.clone(true,true));
$newCard.append($generalForm.clone(true,true));
$newGeneral = getGeneralDetail($newCard);
setGeneralNo($newCard, generateNewGeneralNo());
return $newCard;
}
var deleteDefender = function($card){
deleteGeneralNo($card);
$card.detach();
}
var copyDefender = function($card){
var $general = getGeneralDetail($card);
var generalData = exportGeneralInfo($general);
var $newObj = addDefender($card);
importGeneralInfo(getGeneralDetail($newObj), generalData);
}
var importBattleInfo = function(battleData){
$('.form_load_battle_file').val('');
console.log(battleData);
var $attackerNation = $('.attacker_nation');
var $defenderNation = $('.defender_nation');
var attackerGeneral = battleData.attackerGeneral;
var attackerCity = battleData.attackerCity;
var attackerNation = battleData.attackerNation;
var defenderGenerals = battleData.defenderGenerals;
var defenderCity = battleData.defenderCity;
var defenderNation = battleData.defenderNation;
$('#year').val(battleData.year);
$('#month').val(battleData.month);
$('#repeat_cnt').val(battleData.repeatCnt);
$('.delete-defender').click();
$attackerNation.find('.form_nation_type').val(attackerNation.type);
$attackerNation.find('.form_tech').val(Math.floor(attackerNation.tech/1000));
$attackerNation.find('.form_nation_level').val(attackerNation.level);
if(attackerNation.capital == 1){
$attackerNation.find('.form_is_capital:first').click();
}
else{
$attackerNation.find('.form_is_capital:last').click();
}
$attackerNation.find('.form_city_level').val(attackerCity.level);
importGeneralInfo($('.attacker_form'), attackerGeneral);
$defenderNation.find('.form_nation_type').val(defenderNation.type);
$defenderNation.find('.form_tech').val(Math.floor(defenderNation.tech/1000));
$defenderNation.find('.form_nation_level').val(defenderNation.level);
if(defenderNation.capital == 1){
$defenderNation.find('.form_is_capital:first').click();
}
else{
$defenderNation.find('.form_is_capital:last').click();
}
$defenderNation.find('.form_city_level').val(defenderCity.level);
$('#city_def').val(defenderCity.def);
$('#city_wall').val(defenderCity.wall);
$.each(defenderGenerals, function(idx, defenderGeneral){
var $card = addDefender();
importGeneralInfo($card, defenderGeneral);
});
}
var exportAllData = function(){
var $attackerNation = $('.attacker_nation');
var $defenderNation = $('.defender_nation');
var attackerGeneral = exportGeneralInfo($('.attacker_form'));
var attackerCity = {
level:parseInt($attackerNation.find('.form_city_level').val()),
};
var attackerNation = {
type:$attackerNation.find('.form_nation_type').val(),
tech:parseInt($attackerNation.find('.form_tech').val()) * 1000,
level:parseInt($attackerNation.find('.form_nation_level').val()),
capital:$attackerNation.find('.form_is_capital:checked').val()=='1'?1:2,
}
var defenderGenerals = $('.defender_form').map(function(){
return exportGeneralInfo($(this));
}).toArray();
var defenderCity = {
def: parseInt($('#city_def').val()),
wall: parseInt($('#city_wall').val()),
level:parseInt($defenderNation.find('.form_city_level').val()),
};
var defenderNation = {
type:$defenderNation.find('.form_nation_type').val(),
tech:parseInt($defenderNation.find('.form_tech').val()) * 1000,
level:parseInt($defenderNation.find('.form_nation_level').val()),
capital:$defenderNation.find('.form_is_capital:checked').val()=='1'?3:4,
}
var year = parseInt($('#year').val());
var month = parseInt($('#month').val());
var repeatCnt = parseInt($('#repeat_cnt').val());
return {
attackerGeneral:attackerGeneral,
attackerCity:attackerCity,
attackerNation:attackerNation,
defenderGenerals:defenderGenerals,
defenderCity:defenderCity,
defenderNation:defenderNation,
year:year,
month:month,
repeatCnt:repeatCnt,
};
}
var extendAllDataForDB = function(allData){
var defaultNation = {
nation:0,
name:'재야',
capital:0,
level:0,
gold:0,
rice:2000,
type:'None',
tech:0,
gennum:200,
};
var defaultCity = {
nation:0,
supply:1,
name:'도시',
pop:500000,
agri:10000,
comm:10000,
secu:10000,
def:1000,
wall:1000,
trust:100,
pop_max:600000,
agri_max:12000,
comm_max:12000,
secu_max:10000,
def_max:12000,
wall_max:12000,
dead:0,
state:0,
conflict:'{}',
};
var attackerNation = $.extend({}, defaultNation, allData.attackerNation);
attackerNation.nation = 1;
attackerNation.name = '출병국';
var attackerCity = $.extend({}, defaultCity, allData.attackerCity);
attackerCity.nation = 1;
attackerCity.city = 1;
var attackerGeneral = extendGeneralInfoForDB(allData.attackerGeneral);
if(2 <= attackerGeneral.officer_level && attackerGeneral.officer_level <= 4){
attackerGeneral.officer_city = 1;
}
else{
attackerGeneral.officer_city = 0;
}
var defenderNation = $.extend({}, defaultNation, allData.defenderNation);
defenderNation.nation = 2;
defenderNation.name = '수비국';
var defenderCity = $.extend({}, defaultCity, allData.defenderCity);
defenderCity.nation = 2;
defenderCity.city = 3;
defenderCity.wall_max = defenderCity.wall/5*6;
defenderCity.def_max = defenderCity.def/5*6;
var defenderGenerals = [];
$.each(allData.defenderGenerals, function(){
var defenderGeneral = extendGeneralInfoForDB(this);
if(2 <= defenderGeneral.officer_level && defenderGeneral.officer_level <= 4){
defenderGeneral.officer_city = 3;
}
else{
defenderGeneral.officer_city = 0;
}
defenderGenerals.push(defenderGeneral);
});
return $.extend({}, allData, {
attackerGeneral:attackerGeneral,
attackerCity:attackerCity,
attackerNation:attackerNation,
defenderGenerals:defenderGenerals,
defenderCity:defenderCity,
defenderNation:defenderNation,
});
}
var parseSkillCount = function(skills){
var result = [];
$.each(skills, function(key, value){
result.push("{0}({1}회)".format(key, toPretty(value)));
})
if(result.length == 0){
return '-';
}
return result.join(', ');
}
var toPretty = function(number){
if(isInt(number)){
number = parseInt(number);
}
else{
number = parseFloat(number).toFixed(2);
}
return numberWithCommas(number);
}
var showBattleResult = function(result){
$('#result_datetime').html(result.datetime);
$('#result_warcnt').html(toPretty(result.avgWar));
$('#result_phase').html(toPretty(result.phase));
$('#result_killed').html(toPretty(result.killed));
if(result.minKilled != result.maxKilled){
$('#result_maxKilled').html(toPretty(result.maxKilled));
$('#result_minKilled').html(toPretty(result.minKilled));
$('#result_varKilled').show();
}
else{
$('#result_varKilled').hide();
}
$('#result_dead').html(toPretty(result.dead));
if(result.minDead != result.maxDead){
$('#result_maxDead').html(toPretty(result.maxDead));
$('#result_minDead').html(toPretty(result.minDead));
$('#result_varDead').show();
}
else{
$('#result_varDead').hide();
}
$('#result_attackerRice').html(toPretty(result.attackerRice));
$('#result_defenderRice').html(toPretty(result.defenderRice));
$('#result_attackerSkills').html(parseSkillCount(result.attackerSkills));
$('.result_defenderSkills').detach();
var $summary = $('#battle_result_summary');
$.each(result.defendersSkills, function(idx, defenderSkills){
console.log(defenderSkills);
var $result = $("<tr class='result_defenderSkills'><th>수비자{0} 스킬</th><td></td></tr>".format(idx + 1));
$result.find('td').html(parseSkillCount(defenderSkills));
$summary.append($result);
});
$('#generalBattleResultLog').html(result.lastWarLog.generalBattleResultLog);
$('#generalBattleDetailLog').html(result.lastWarLog.generalBattleDetailLog);
}
var beginBattle = function(){
var data = extendAllDataForDB(exportAllData());
console.log(data);
$.ajax({
type:'post',
url:'j_simulate_battle.php',
dataType:'json',
data:{
action:'battle',
query:JSON.stringify(data),
}
}).then(function(result){
console.log(result);
if(!result.result){
alert(result.reason);
return;
}
showBattleResult(result);
}, function(result){
alert('전투 개시 실패!');
});
}
var reorderDefender = function(defenderOrder){
$.each(defenderOrder, function(idx, generalNo){
if(!(generalNo in defenderNoList)){
//음..?
alert("{0}이 수비자 리스트에 없습니다. 버그인 듯 합니다.".format(generalNo));
return true;
}
var $defenderObj = defenderNoList[generalNo];
$defenderObj.detach();
$defenderColumn.append($defenderObj);
})
}
var requestReorderDefender = function(){
var data = extendAllDataForDB(exportAllData());
console.log(data);
$.ajax({
type:'post',
url:'j_simulate_battle.php',
dataType:'json',
data:{
action:'reorder',
query:JSON.stringify(data),
}
}).then(function(result){
console.log(result);
if(!result.result){
alert(result.reason);
return;
}
reorderDefender(result.order);
}, function(result){
alert('재정렬 실패!');
});
}
initBasicEvent();
$attackerCard.append($generalForm.clone(true,true));
addDefender();
$('.btn-begin_battle').click(function(){
beginBattle();
});
$('.btn-reorder_defender').click(function(){
requestReorderDefender();
})
jQuery(function($) {
var $generalForm = $('.form_sample .general_detail');
var $defenderHeaderForm = $('.form_sample .card-header');
var $defenderColumn = $('.defender-column');
var defenderNoList = {};
var $attackerCard = $('.attacker_form');
var initBasicEvent = function() {
if (window.nation) {
$('.form_city_level').val(window.city.level);
$('.form_def').val(parseInt(window.city.def));
$('.form_wall').val(parseInt(window.city.wall));
$('.form_nation_type').val(window.nation.type);
$('.form_nation_level').val(window.nation.level);
$('.form_tech').val(parseInt(window.nation.tech / 1000));
if (window.nation.capital == window.city.city) {
$('.attacker_nation .form_is_capital:first').click();
$('.defender_nation .form_is_capital:first').click();
} else {
$('.attacker_nation .form_is_capital:last').click();
$('.defender_nation .form_is_capital:last').click();
}
} else {
$('.attacker_nation .form_is_capital:last').click();
$('.defender_nation .form_is_capital:last').click();
}
$('.form_injury').change(function() {
var $this = $(this);
var $general = getGeneralDetail($this);
var $helptext = $general.find('.injury_helptext');
var injury = parseInt($this.val());
//FIXME: PHP 코드와 항상 일치하도록 변경
var text = '건강';
var color = 'white';
if (injury > 60) {
text = '위독';
color = 'red';
} else if (injury > 40) {
text = '심각';
color = 'magenta';
} else if (injury > 20) {
text = '중상';
color = 'orange';
} else if (injury > 0) {
text = '경상';
color = 'yellow';
}
$helptext.html(text).css('color', color);
});
$('.export_general').click(function() {
var $btn = $(this);
var $general = getGeneralDetail($btn);
var values = exportGeneralInfo($general);
console.log(values);
});
$('.delete-defender').click(function() {
var $card = getGeneralFrame($(this));
deleteDefender($card);
});
$('.copy-defender').click(function() {
var $card = getGeneralFrame($(this));
copyDefender($card);
});
$('.add-defender').click(function() {
addDefender();
});
$('.btn-general-load').click(function() {
var $file = $(this).prev();
$file[0].click();
})
$('.form_load_general_file').on('change', function(e) {
e.preventDefault();
var $this = $(this);
var $card = getGeneralFrame($this);
var files = e.target.files;
importGeneralInfoByFile(files, $card);
return false;
});
$('.btn-general-import-server').click(function() {
var $this = $(this);
var $card = getGeneralFrame($this);
var $modal = $('#importModal');
$modal.data('target', $card);
$modal.modal('show');
});
$('.btn-general-save').click(function() {
var $this = $(this);
var $general = getGeneralDetail($this);
var generalData = exportGeneralInfo($general);
var filename = "general_{0}.json".format(generalData.name);
var saveData = JSON.stringify({
objType: 'general',
data: generalData
}, null, 4);
download(saveData, filename, 'application/json');
});
$('.btn-battle-load').click(function() {
var $file = $(this).prev();
$file[0].click();
})
$('.form_load_battle_file').on('change', function(e) {
e.preventDefault();
var $this = $(this);
var files = e.target.files;
importBattleInfoByFile(files);
return false;
});
$('.btn-battle-save').click(function() {
var battleData = exportAllData();
var filename = "battle_{0}.json".format(moment().format('YYYYMMDD_hhmmss'));
var saveData = JSON.stringify({
objType: 'battle',
data: battleData
}, null, 4);
download(saveData, filename, 'application/json');
})
var $generals = $('.general_detail');
$generals.bind('dragover dragleave', function(e) {
e.stopPropagation()
e.preventDefault()
})
$generals.bind('drop', function(e) {
e.preventDefault();
var $this = $(this);
var $card = getGeneralFrame($this);
var files = e.originalEvent.dataTransfer.files;
importGeneralInfoByFile(files, $card);
return false;
});
var $battlePad = $('.dragpad_battle');
$battlePad.bind('dragover dragleave', function(e) {
e.stopPropagation()
e.preventDefault()
})
$battlePad.bind('drop', function(e) {
e.preventDefault();
var files = e.originalEvent.dataTransfer.files;
importBattleInfoByFile(files);
return false;
});
}
var importGeneralInfo = function($general, data) {
var setVal = function(query, val) {
$general.find(query).val(val).change();
}
setVal('.form_general_name', data.name);
setVal('.form_officer_level', data.officer_level);
setVal('.form_exp_level', data.explevel);
setVal('.form_leadership', data.leadership);
setVal('.form_general_horse', data.horse);
setVal('.form_strength', data.strength);
setVal('.form_general_weap', data.weapon);
setVal('.form_intel', data.intel);
setVal('.form_general_book', data.book);
setVal('.form_general_item', data.item);
setVal('.form_injury', data.injury);
setVal('.form_rice', data.rice);
setVal('.form_general_character', data.personal);
setVal('.form_general_special_war', data.special2);
setVal('.form_crew', data.crew);
setVal('.form_crewtype', data.crewtype);
setVal('.form_atmos', data.atmos);
setVal('.form_train', data.train);
setVal('.form_dex1', data.dex1);
setVal('.form_dex2', data.dex2);
setVal('.form_dex3', data.dex3);
setVal('.form_dex4', data.dex4);
setVal('.form_dex5', data.dex5);
setVal('.form_defence_train', data.defence_train);
setVal('.form_warnum', data.warnum);
setVal('.form_killnum', data.killnum);
setVal('.form_killcrew', data.killcrew);
if (!setGeneralNo($general, data.no)) {
setGeneralNo($general, generateNewGeneralNo());
}
}
var exportGeneralInfo = function($general) {
var getInt = function(query) {
return parseInt($general.find(query).val());
}
var getVal = function(query) {
return $general.find(query).val();
}
return {
no: getGeneralNo($general),
name: getVal('.form_general_name'),
officer_level: getInt('.form_officer_level'),
explevel: getInt('.form_exp_level'),
leadership: getInt('.form_leadership'),
horse: getVal('.form_general_horse'),
strength: getInt('.form_strength'),
weapon: getVal('.form_general_weap'),
intel: getInt('.form_intel'),
book: getVal('.form_general_book'),
item: getVal('.form_general_item'),
injury: getInt('.form_injury'),
rice: getInt('.form_rice'),
personal: getVal('.form_general_character'),
special2: getVal('.form_general_special_war'),
crew: getInt('.form_crew'),
crewtype: getInt('.form_crewtype'),
atmos: getInt('.form_atmos'),
train: getInt('.form_train'),
dex1: getInt('.form_dex1'),
dex2: getInt('.form_dex2'),
dex3: getInt('.form_dex3'),
dex4: getInt('.form_dex4'),
dex5: getInt('.form_dex5'),
defence_train: getInt('.form_defence_train'),
warnum: getInt('.form_warnum'),
killnum: getInt('.form_killnum'),
killcrew: getInt('.form_killcrew'),
};
}
var importBattleInfoByFile = function(files) {
if (files === null) {
alert('파일 에러!');
return false;
}
if (files.length < 1) {
alert("파일 에러!");
return false;
}
var file = files[0];
if (file.size > 1024 * 1024) {
alert('파일이 너무 큽니다!');
return false;
}
if (file.type === '') {
alert('폴더를 업로드할 수 없습니다!');
return false;
}
var reader = new FileReader();
reader.onload = function() {
var battleData = {};
try {
battleData = JSON.parse(reader.result);
} catch (e) {
alert('올바르지 않은 파일 형식입니다');
return false;
}
if (!('objType' in battleData)) {
alert('파일 형식을 확인할 수 없습니다');
return false;
}
if (battleData.objType != 'battle') {
alert('전투 데이터가 아닙니다');
return false;
}
importBattleInfo(battleData.data);
return true;
};
try {
reader.readAsText(file);
} catch (e) {
alert('파일을 읽는데 실패했습니다.');
return false;
}
return true;
}
var importGeneralInfoByFile = function(files, $card) {
if ($card === undefined) {
$card = addDefender();
}
if (files === null) {
alert('파일 에러!');
return false;
}
if (files.length < 1) {
alert("파일 에러!");
return false;
}
var file = files[0];
if (file.size > 1024 * 1024) {
alert('파일이 너무 큽니다!');
return false;
}
if (file.type === '') {
alert('폴더를 업로드할 수 없습니다!');
return false;
}
var reader = new FileReader();
reader.onload = function() {
var generalData = {};
try {
generalData = JSON.parse(reader.result);
} catch (e) {
alert('올바르지 않은 파일 형식입니다');
return false;
}
if (!('objType' in generalData)) {
alert('파일 형식을 확인할 수 없습니다');
return false;
}
if (generalData.objType == 'battle') {
importBattleInfo(generalData.data);
return true;
}
if (generalData.objType != 'general') {
alert('장수 데이터가 아닙니다');
return false;
}
$card.find('.form_load_general_file').val('');
importGeneralInfo($card, generalData.data);
return true;
};
try {
reader.readAsText(file);
} catch (e) {
alert('파일을 읽는데 실패했습니다.');
return false;
}
return true;
}
var extendGeneralInfoForDB = function(generalData) {
var dbVal = {
nation: (generalData.no) <= 1 ? 1 : 2,
city: (generalData.no) <= 1 ? 1 : 3,
turntime: '2018-08-26 12:00',
special: defaultSpecialDomestic,
leadership_exp: 0,
strength_exp: 0,
intel_exp: 0,
gold: 10000,
dedication: 0,
recent_war: '2018-08-26 12:00',
experience: Math.pow(generalData.explevel, 2),
};
return $.extend({}, generalData, dbVal);
}
var getGeneralFrame = function($btn) {
var $card = $btn.closest('.general_form');
return $card;
}
var getGeneralDetail = function($btn) {
var $card = getGeneralFrame($btn);
var $general = $card.find('.general_detail');
return $general;
}
var getGeneralNo = function($btn) {
return parseInt(getGeneralFrame($btn).data('general_no'));
}
var setGeneralNo = function($btn, value) {
if (value == 1) {
//1번은 무조건 공격자임
return false;
}
if (value in defenderNoList) {
return false;
}
var $card = getGeneralFrame($btn);
$card.data('general_no', value);
defenderNoList[value] = $card;
return true;
}
var generateNewGeneralNo = function() {
while (true) {
var newGeneralNo = parseInt(Math.random() * (1 << 24)) + 2;
if (newGeneralNo in defenderNoList) {
continue;
}
return newGeneralNo;
}
}
var deleteGeneralNo = function($btn) {
var $card = getGeneralFrame($btn);
$card.removeData('general_no');
var generalNo = getGeneralNo($card);
delete defenderNoList[generalNo];
}
var addDefender = function($cardAfter) {
var $newCard = $('<div class="card mb-2 defender_form general_form"></div>');
if ($cardAfter === undefined) {
$defenderColumn.append($newCard);
} else {
$cardAfter.after($newCard);
}
$newCard.append($defenderHeaderForm.clone(true, true));
$newCard.append($generalForm.clone(true, true));
$newGeneral = getGeneralDetail($newCard);
setGeneralNo($newCard, generateNewGeneralNo());
return $newCard;
}
var deleteDefender = function($card) {
deleteGeneralNo($card);
$card.detach();
}
var copyDefender = function($card) {
var $general = getGeneralDetail($card);
var generalData = exportGeneralInfo($general);
var $newObj = addDefender($card);
importGeneralInfo(getGeneralDetail($newObj), generalData);
}
var importBattleInfo = function(battleData) {
$('.form_load_battle_file').val('');
console.log(battleData);
var $attackerNation = $('.attacker_nation');
var $defenderNation = $('.defender_nation');
var attackerGeneral = battleData.attackerGeneral;
var attackerCity = battleData.attackerCity;
var attackerNation = battleData.attackerNation;
var defenderGenerals = battleData.defenderGenerals;
var defenderCity = battleData.defenderCity;
var defenderNation = battleData.defenderNation;
$('#year').val(battleData.year);
$('#month').val(battleData.month);
$('#repeat_cnt').val(battleData.repeatCnt);
$('.delete-defender').click();
$attackerNation.find('.form_nation_type').val(attackerNation.type);
$attackerNation.find('.form_tech').val(Math.floor(attackerNation.tech / 1000));
$attackerNation.find('.form_nation_level').val(attackerNation.level);
if (attackerNation.capital == 1) {
$attackerNation.find('.form_is_capital:first').click();
} else {
$attackerNation.find('.form_is_capital:last').click();
}
$attackerNation.find('.form_city_level').val(attackerCity.level);
importGeneralInfo($('.attacker_form'), attackerGeneral);
$defenderNation.find('.form_nation_type').val(defenderNation.type);
$defenderNation.find('.form_tech').val(Math.floor(defenderNation.tech / 1000));
$defenderNation.find('.form_nation_level').val(defenderNation.level);
if (defenderNation.capital == 1) {
$defenderNation.find('.form_is_capital:first').click();
} else {
$defenderNation.find('.form_is_capital:last').click();
}
$defenderNation.find('.form_city_level').val(defenderCity.level);
$('#city_def').val(defenderCity.def);
$('#city_wall').val(defenderCity.wall);
$.each(defenderGenerals, function(idx, defenderGeneral) {
var $card = addDefender();
importGeneralInfo($card, defenderGeneral);
});
}
var exportAllData = function() {
var $attackerNation = $('.attacker_nation');
var $defenderNation = $('.defender_nation');
var attackerGeneral = exportGeneralInfo($('.attacker_form'));
var attackerCity = {
level: parseInt($attackerNation.find('.form_city_level').val()),
};
var attackerNation = {
type: $attackerNation.find('.form_nation_type').val(),
tech: parseInt($attackerNation.find('.form_tech').val()) * 1000,
level: parseInt($attackerNation.find('.form_nation_level').val()),
capital: $attackerNation.find('.form_is_capital:checked').val() == '1' ? 1 : 2,
}
var defenderGenerals = $('.defender_form').map(function() {
return exportGeneralInfo($(this));
}).toArray();
var defenderCity = {
def: parseInt($('#city_def').val()),
wall: parseInt($('#city_wall').val()),
level: parseInt($defenderNation.find('.form_city_level').val()),
};
var defenderNation = {
type: $defenderNation.find('.form_nation_type').val(),
tech: parseInt($defenderNation.find('.form_tech').val()) * 1000,
level: parseInt($defenderNation.find('.form_nation_level').val()),
capital: $defenderNation.find('.form_is_capital:checked').val() == '1' ? 3 : 4,
}
var year = parseInt($('#year').val());
var month = parseInt($('#month').val());
var repeatCnt = parseInt($('#repeat_cnt').val());
return {
attackerGeneral: attackerGeneral,
attackerCity: attackerCity,
attackerNation: attackerNation,
defenderGenerals: defenderGenerals,
defenderCity: defenderCity,
defenderNation: defenderNation,
year: year,
month: month,
repeatCnt: repeatCnt,
};
}
var extendAllDataForDB = function(allData) {
var defaultNation = {
nation: 0,
name: '재야',
capital: 0,
level: 0,
gold: 0,
rice: 2000,
type: 'None',
tech: 0,
gennum: 200,
};
var defaultCity = {
nation: 0,
supply: 1,
name: '도시',
pop: 500000,
agri: 10000,
comm: 10000,
secu: 10000,
def: 1000,
wall: 1000,
trust: 100,
pop_max: 600000,
agri_max: 12000,
comm_max: 12000,
secu_max: 10000,
def_max: 12000,
wall_max: 12000,
dead: 0,
state: 0,
conflict: '{}',
};
var attackerNation = $.extend({}, defaultNation, allData.attackerNation);
attackerNation.nation = 1;
attackerNation.name = '출병국';
var attackerCity = $.extend({}, defaultCity, allData.attackerCity);
attackerCity.nation = 1;
attackerCity.city = 1;
var attackerGeneral = extendGeneralInfoForDB(allData.attackerGeneral);
if (2 <= attackerGeneral.officer_level && attackerGeneral.officer_level <= 4) {
attackerGeneral.officer_city = 1;
} else {
attackerGeneral.officer_city = 0;
}
var defenderNation = $.extend({}, defaultNation, allData.defenderNation);
defenderNation.nation = 2;
defenderNation.name = '수비국';
var defenderCity = $.extend({}, defaultCity, allData.defenderCity);
defenderCity.nation = 2;
defenderCity.city = 3;
defenderCity.wall_max = parseInt(defenderCity.wall / 5 * 6);
defenderCity.def_max = parseInt(defenderCity.def / 5 * 6);
var defenderGenerals = [];
$.each(allData.defenderGenerals, function() {
var defenderGeneral = extendGeneralInfoForDB(this);
if (2 <= defenderGeneral.officer_level && defenderGeneral.officer_level <= 4) {
defenderGeneral.officer_city = 3;
} else {
defenderGeneral.officer_city = 0;
}
defenderGenerals.push(defenderGeneral);
});
return $.extend({}, allData, {
attackerGeneral: attackerGeneral,
attackerCity: attackerCity,
attackerNation: attackerNation,
defenderGenerals: defenderGenerals,
defenderCity: defenderCity,
defenderNation: defenderNation,
});
}
var parseSkillCount = function(skills) {
var result = [];
$.each(skills, function(key, value) {
result.push("{0}({1}회)".format(key, toPretty(value)));
})
if (result.length == 0) {
return '-';
}
return result.join(', ');
}
var toPretty = function(number) {
if (isInt(number)) {
number = parseInt(number);
} else {
number = parseFloat(number).toFixed(2);
}
return numberWithCommas(number);
}
var showBattleResult = function(result) {
$('#result_datetime').html(result.datetime);
$('#result_warcnt').html(toPretty(result.avgWar));
$('#result_phase').html(toPretty(result.phase));
$('#result_killed').html(toPretty(result.killed));
if (result.minKilled != result.maxKilled) {
$('#result_maxKilled').html(toPretty(result.maxKilled));
$('#result_minKilled').html(toPretty(result.minKilled));
$('#result_varKilled').show();
} else {
$('#result_varKilled').hide();
}
$('#result_dead').html(toPretty(result.dead));
if (result.minDead != result.maxDead) {
$('#result_maxDead').html(toPretty(result.maxDead));
$('#result_minDead').html(toPretty(result.minDead));
$('#result_varDead').show();
} else {
$('#result_varDead').hide();
}
$('#result_attackerRice').html(toPretty(result.attackerRice));
$('#result_defenderRice').html(toPretty(result.defenderRice));
$('#result_attackerSkills').html(parseSkillCount(result.attackerSkills));
$('.result_defenderSkills').detach();
var $summary = $('#battle_result_summary');
$.each(result.defendersSkills, function(idx, defenderSkills) {
console.log(defenderSkills);
var $result = $("<tr class='result_defenderSkills'><th>수비자{0} 스킬</th><td></td></tr>".format(idx + 1));
$result.find('td').html(parseSkillCount(defenderSkills));
$summary.append($result);
});
$('#generalBattleResultLog').html(result.lastWarLog.generalBattleResultLog);
$('#generalBattleDetailLog').html(result.lastWarLog.generalBattleDetailLog);
}
var beginBattle = function() {
var data = extendAllDataForDB(exportAllData());
console.log(data);
$.ajax({
type: 'post',
url: 'j_simulate_battle.php',
dataType: 'json',
data: {
action: 'battle',
query: JSON.stringify(data),
}
}).then(function(result) {
console.log(result);
if (!result.result) {
alert(result.reason);
return;
}
showBattleResult(result);
}, function(result) {
alert('전투 개시 실패!');
});
}
var reorderDefender = function(defenderOrder) {
$.each(defenderOrder, function(idx, generalNo) {
if (!(generalNo in defenderNoList)) {
//음..?
alert("{0}이 수비자 리스트에 없습니다. 버그인 듯 합니다.".format(generalNo));
return true;
}
var $defenderObj = defenderNoList[generalNo];
$defenderObj.detach();
$defenderColumn.append($defenderObj);
})
}
var requestReorderDefender = function() {
var data = extendAllDataForDB(exportAllData());
console.log(data);
$.ajax({
type: 'post',
url: 'j_simulate_battle.php',
dataType: 'json',
data: {
action: 'reorder',
query: JSON.stringify(data),
}
}).then(function(result) {
console.log(result);
if (!result.result) {
alert(result.reason);
return;
}
reorderDefender(result.order);
}, function(result) {
alert('재정렬 실패!');
});
}
var initGeneralList = false;
$('#importFromDB').click(function() {
var generalID = $('#modalSelector').val();
console.log(generalID);
$.post({
url: 'j_export_simulator_object.php',
dataType: 'json',
data: {
destGeneralID: generalID
}
}).then(function(data) {
if (!data.result) {
alert(data.reason);
return false;
}
var $modal = $('#importModal');
var $card = $modal.data('target');
importGeneralInfo($card, data.general);
$modal.modal('hide');
}, errUnknown);
});
$('#importModal').on('show.bs.modal', function(e) {
if (!initGeneralList) {
var $list = $('#modalSelector');
var addNation = function(generalList, nationName, color) {
generalList.sort(function(lhs, rhs) {
if (lhs.npc != rhs.npc) {
return lhs.npc - rhs.npc;
}
if (lhs.name < rhs.name) {
return -1;
}
if (lhs.name > rhs.name) {
return 1;
}
return 0;
})
var $optGroup = $('<optgroup label="{0}"></optgroup>'.format(nationName));
$optGroup.css('background-color', color);
$optGroup.css('color', isBrightColor(color) ? 'black' : 'white');
$.each(generalList, function(idx, general) {
$item = $('<option value="{0}">{1}</option>'.format(general.no, general.name));
if (general.npc) {
$item.css('color', getNpcColor(general.npc));
} else {
$item.css('color', 'white');
}
$item.css('background-color', 'black');
$optGroup.append($item);
});
$list.append($optGroup);
}
$.post({
url: 'j_get_basic_general_list.php',
dataType: 'json',
data: {
req: 2,
}
}).then(function(data) {
if (!data.result) {
alert(data.reason);
$('#importModal').modal('hide');
return false;
}
var nations = data.nation;
var myNationID = data.nationID;
$list.empty();
//자국 먼저
if (0 in data.list) {
nations[0] = {
nation: 0,
name: '재야',
color: '#000000'
};
}
addNation(combineArray(data.list[myNationID], data.column), nations[myNationID].name, nations[myNationID].color);
for (var nationID in data.list) {
if (nationID == myNationID) {
continue;
}
addNation(combineArray(data.list[nationID], data.column), nations[nationID].name, nations[nationID].color);
}
initGeneralList = true;
}, errUnknown);
}
});
initBasicEvent();
$attackerCard.append($generalForm.clone(true, true));
addDefender();
$('.btn-begin_battle').click(function() {
beginBattle();
});
$('.btn-reorder_defender').click(function() {
requestReorderDefender();
})
});
+194 -200
View File
@@ -1,201 +1,195 @@
function changePermission(isAmbassador, rawGeneralList){
console.log(isAmbassador);
console.log(rawGeneralList);
var generalList = [];
$.each(rawGeneralList, function(idx, value){
generalList.push(parseInt(value.id));
})
$.post({
url:'j_general_set_permission.php',
dataType:'json',
data:{
isAmbassador:isAmbassador,
genlist:generalList
},
}).then(function(data){
if(!data){
alert('변경하지 못했습니다.');
return false;
}
if(!data.result){
alert('변경하지 못했습니다. : '+data.reason);
return false;
}
alert('변경했습니다.');
location.reload();
}, errUnknown);
}
$(function(){
$('#selectAmbassador').select2({
theme: 'bootstrap4',
placeholder: "",
allowClear: true,
language: "ko",
width:300,
maximumSelectionLength: 2,
containerCss: {
display: "inline-block !important;",
color: 'white !important'
},
data:candidateAmbassadors,
//containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
});
$('#selectAuditor').select2({
theme: 'bootstrap4',
placeholder: "",
allowClear: true,
language: "ko",
width:300,
maximumSelectionLength: 2,
containerCss: {
display: "inline-block !important;",
color: 'white !important'
},
data:candidateAuditors,
//containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
});
$('#changeAmbassador').click(function(){
if(!confirm('외교권자를 변경할까요?')){
return false;
}
changePermission(true, $('#selectAmbassador').select2('data'));
return false;
});
$('#changeAuditor').click(function(){
if(!confirm('조언자를 변경할까요?')){
return false;
}
changePermission(false, $('#selectAuditor').select2('data'));
return false;
});
$('#btn_kick').click(function(){
var $kickSelect = $('#genlist_kick option:selected');
var generalID = $kickSelect.val();
if(!generalID){
alert('장수를 선택해주세요');
return false;
}
var generalName = $kickSelect.data('name');
if(!confirm('{0}를 추방하시겠습니까?'.format(generalName))){
return false;
}
$.post({
url:'j_myBossInfo.php',
dataType:'json',
data:{
action:'추방',
destGeneralID:generalID
},
}).then(function(data){
if(!data){
alert('추방하지 못했습니다.');
return false;
}
if(!data.result){
alert('추방하지 못했습니다. : '+data.reason);
return false;
}
alert('{0}를 추방했습니다.'.format(generalName));
location.reload();
}, errUnknown);
return false;
});
$('.btn_appoint').click(function(){
var $btn = $(this);
var officerLevel = $btn.data('officer_level');
var officerLevelText = $btn.data('officer_level_text');
var cityID = 0;
var cityName = '_';
var $generalSelect = $('#genlist_{0} option:selected'.format(officerLevel));
var $citySelect = $('#citylist_{0} option:selected'.format(officerLevel));
var generalID = $generalSelect.val();
var generalName = $generalSelect.data('name');
var generalOfficerLevel = $generalSelect.data('officer_level');
if(officerLevel >= 5){
if(generalID == 0){
if(!confirm('{0}직을 비우시겠습니까?'.format(officerLevelText))){
return false;
}
}
else if(generalOfficerLevel >= 5){
if(!confirm('이미 수뇌인 {0}을(를) {1}직에 임명하시겠습니까?'.format(generalName, officerLevelText))){
return false;
}
}
else{
if(!confirm('{0}을(를) {1}직에 임명하시겠습니까?'.format(generalName, officerLevelText))){
return false;
}
}
}
else{
cityID = $citySelect.val();
if(!cityID){
alert('도시를 선택해주세요');
return false;
}
cityName = $citySelect.find('option:selected .name_field').text();
if(generalID == 0){
if(!confirm('{0} {1}직을 비우시겠습니까?'.format(cityName, officerLevelText))){
return false;
}
}
else if(generalOfficerLevel >= 5){
if(!confirm('수뇌인 {0}을(를) {1} {2}직에 임명하시겠습니까?'.format(generalName, cityName, officerLevelText))){
return false;
}
}
else{
if(!confirm('{0}을(를) {1} {2}직에 임명하시겠습니까?'.format(generalName, cityName, officerLevelText))){
return false;
}
}
}
$.post({
url:'j_myBossInfo.php',
dataType:'json',
data:{
action:'임명',
destGeneralID:generalID,
destCityID:cityID,
officerLevel:officerLevel
},
}).then(function(data){
if(!data){
alert('임명하지 못했습니다.');
return false;
}
if(!data.result){
alert('임명하지 못했습니다. : '+data.reason);
return false;
}
if(generalID){
alert('{0}을(를) 임명했습니다.'.format(generalName));
}
else{
alert('관직을 비웠습니다.');
}
location.reload();
}, errUnknown);
})
function changePermission(isAmbassador, rawGeneralList) {
console.log(isAmbassador);
console.log(rawGeneralList);
var generalList = [];
$.each(rawGeneralList, function(idx, value) {
generalList.push(parseInt(value.id));
})
$.post({
url: 'j_general_set_permission.php',
dataType: 'json',
data: {
isAmbassador: isAmbassador,
genlist: generalList
},
}).then(function(data) {
if (!data) {
alert('변경하지 못했습니다.');
return false;
}
if (!data.result) {
alert('변경하지 못했습니다. : ' + data.reason);
return false;
}
alert('변경했습니다.');
location.reload();
}, errUnknown);
}
$(function() {
$('#selectAmbassador').select2({
theme: 'bootstrap4',
placeholder: "",
allowClear: true,
language: "ko",
width: 300,
maximumSelectionLength: 2,
containerCss: {
display: "inline-block !important;",
color: 'white !important'
},
data: candidateAmbassadors,
//containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
});
$('#selectAuditor').select2({
theme: 'bootstrap4',
placeholder: "",
allowClear: true,
language: "ko",
width: 300,
maximumSelectionLength: 2,
containerCss: {
display: "inline-block !important;",
color: 'white !important'
},
data: candidateAuditors,
//containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
});
$('#changeAmbassador').click(function() {
if (!confirm('외교권자를 변경할까요?')) {
return false;
}
changePermission(true, $('#selectAmbassador').select2('data'));
return false;
});
$('#changeAuditor').click(function() {
if (!confirm('조언자를 변경할까요?')) {
return false;
}
changePermission(false, $('#selectAuditor').select2('data'));
return false;
});
$('#btn_kick').click(function() {
var $kickSelect = $('#genlist_kick option:selected');
var generalID = $kickSelect.val();
if (!generalID) {
alert('장수를 선택해주세요');
return false;
}
var generalName = $kickSelect.data('name');
if (!confirm('{0}를 추방하시겠습니까?'.format(generalName))) {
return false;
}
$.post({
url: 'j_myBossInfo.php',
dataType: 'json',
data: {
action: '추방',
destGeneralID: generalID
},
}).then(function(data) {
if (!data) {
alert('추방하지 못했습니다.');
return false;
}
if (!data.result) {
alert('추방하지 못했습니다. : ' + data.reason);
return false;
}
alert('{0}를 추방했습니다.'.format(generalName));
location.reload();
}, errUnknown);
return false;
});
$('.btn_appoint').click(function() {
var $btn = $(this);
var officerLevel = $btn.data('officer_level');
var officerLevelText = $btn.data('officer_level_text');
var cityID = 0;
var cityName = '_';
var $generalSelect = $('#genlist_{0} option:selected'.format(officerLevel));
var $citySelect = $('#citylist_{0} option:selected'.format(officerLevel));
var generalID = parseInt($generalSelect.val());
var generalName = $generalSelect.data('name');
var generalOfficerLevel = $generalSelect.data('officer_level');
if (officerLevel >= 5) {
if (generalID == 0) {
if (!confirm('{0}직을 비우시겠습니까?'.format(officerLevelText))) {
return false;
}
} else if (generalOfficerLevel >= 5) {
if (!confirm('이미 수뇌인 {0}을(를) {1}직에 임명하시겠습니까?'.format(generalName, officerLevelText))) {
return false;
}
} else {
if (!confirm('{0}을(를) {1}직에 임명하시겠습니까?'.format(generalName, officerLevelText))) {
return false;
}
}
} else {
cityID = $citySelect.val();
if (!cityID) {
alert('도시를 선택해주세요');
return false;
}
cityName = $citySelect.find('option:selected .name_field').text();
if (generalID == 0) {
if (!confirm('{0} {1}직을 비우시겠습니까?'.format(cityName, officerLevelText))) {
return false;
}
} else if (generalOfficerLevel >= 5) {
if (!confirm('수뇌인 {0}을(를) {1} {2}직에 임명하시겠습니까?'.format(generalName, cityName, officerLevelText))) {
return false;
}
} else {
if (!confirm('{0}을(를) {1} {2}직에 임명하시겠습니까?'.format(generalName, cityName, officerLevelText))) {
return false;
}
}
}
$.post({
url: 'j_myBossInfo.php',
dataType: 'json',
data: {
action: '임명',
destGeneralID: generalID,
destCityID: cityID,
officerLevel: officerLevel
},
}).then(function(data) {
if (!data) {
alert('임명하지 못했습니다.');
return false;
}
if (!data.result) {
alert('임명하지 못했습니다. : ' + data.reason);
return false;
}
if (generalID) {
alert('{0}을(를) 임명했습니다.'.format(generalName));
} else {
alert('관직을 비웠습니다.');
}
location.reload();
}, errUnknown);
})
})
+184 -164
View File
@@ -1,165 +1,185 @@
var filledChiefList = {};
var chiefTableObj = {};
function clearTable(){
$('.chiefLevelText').html('-');
$('.chiefTurnTime, .chiefTurnText, .chiefName').html('&nbsp;');
}
function genChiefTableObj(){
var objTable = {
btns: $('#turnPush,#turnPull,#setCommand')
};
for(var chiefIdx = 5; chiefIdx <= 12; chiefIdx++){
var $plate = $('#chief_{0}'.format(chiefIdx));
var $officerLevelText = $plate.find('.chiefLevelText');
var $name = $plate.find('.chiefName');
var turn = [];
for(var turnIdx=0;turnIdx<maxChiefTurn;turnIdx++){
var $turn = $plate.find('.turn{0}'.format(turnIdx));
var $turnTime = $turn.find('.chiefTurnTime');
var $turnPad = $turn.find('.chiefTurnPad');
var $turnText = $turn.find('.chiefTurnText');
turn.push({turnTime:$turnTime,turnPad:$turnPad,turnText:$turnText});
}
objTable[chiefIdx] = {
officerLevelText: $officerLevelText,
name: $name,
turn: turn
};
}
return objTable;
}
function clearChief(chiefIdx){
var $plate = $('#chief_{0}'.format(chiefIdx));
$plate.find('.chiefLevelText').html('-');
$plate.find('.chiefTurnTime, .chiefTurnText, .chiefName').html('&nbsp;');
}
function reloadTable(){
$.post({
url:'j_getChiefTurn.php',
dataType:'json',
}).then(function(data){
if(!data.result){
alert(data.reason);
return;
}
var turnTerm = data.turnTerm;
var tmpFilledChiefList = {};
if(data.isChief){
chiefTableObj.btns.css('visibility', 'visible');
}
else{
chiefTableObj.btns.css('visibility', 'hidden');
}
$.each(data.nationTurnBrief, function(chiefIdx, chiefInfo){
tmpFilledChiefList[chiefIdx] = true;
filledChiefList[chiefIdx] = true;
var plateObj = chiefTableObj[chiefIdx];
var $name = $('<span>{0}</span>'.format(chiefInfo.name));
var nameColor = getNpcColor(chiefInfo.npcType);
if(nameColor){
$name.css('color',nameColor);
}
plateObj.officerLevelText.text(chiefInfo.officerLevelText);
plateObj.name.html($name);
var turnTimeObj = moment(chiefInfo.turnTime);
var turnList = plateObj.turn;
$.each(chiefInfo.turn, function(turnIdx, turnText){
turnList[turnIdx].turnTime.text(turnTimeObj.format('hh:mm'));
turnList[turnIdx].turnText.html(turnText).css('font-size', '13px');
var oWidth = turnList[turnIdx].turnPad.innerWidth();
var iWidth = turnList[turnIdx].turnText.outerWidth();
if(iWidth > oWidth * 0.95){
var newFontSize = 13 * oWidth / iWidth * 0.9;
turnList[turnIdx].turnText.css('font-size', '{0}px'.format(newFontSize));
}
turnTimeObj = turnTimeObj.add(turnTerm, 'minute');
});
});
for(var idx=5;idx<=12;idx++){
if(idx in tmpFilledChiefList){
continue;
}
if(idx in filledChiefList){
clearChief(chiefIdx);
}
}
filledChiefList = tmpFilledChiefList;
}, errUnknown);
}
function reserveTurn(turnList, command){
console.log(turnList, command);
$.post({
url:'j_set_chief_command.php',
dataType:'json',
data:{
action:command,
turnList:turnList
}
}).then(function(data){
if(!data.result){
alert(data.reason);
}
reloadTable();
}, errUnknown);
}
function pushTurn(turnCnt){
$.post({
url:'j_chief_turn.php',
dataType:'json',
data:{
amount:turnCnt
}
}).then(function(data){
if(!data.result){
alert(data.reason);
}
reloadTable();
}, errUnknown);
}
jQuery(function($){
chiefTableObj= genChiefTableObj();
reloadTable();
$('#reloadTable').click(reloadTable);
$('#setCommand').click(function(){
var turnList = $('#chiefTurnSelector').val().map(function(v){return parseInt(v);});
var $command = $('#chiefCommandList option:selected');
if($command.data('reqarg')){
$.redirect(
"b_processing.php", {
command: $command.val(),
turnList: turnList.join('_'),
is_chief: true
}, "GET");
}
else{
reserveTurn(turnList, $command.val());
}
return false;
});
$('#turnPush').click(function(){
pushTurn(1);
});
$('#turnPull').click(function(){
pushTurn(-1);
});
var filledChiefList = {};
var chiefTableObj = {};
function clearTable(){
$('.chiefLevelText').html('-');
$('.chiefTurnTime, .chiefTurnText, .chiefName').html('&nbsp;');
}
function genChiefTableObj(){
var objTable = {
btns: $('#turnPush,#turnPull,#setCommand')
};
for(var chiefIdx = 5; chiefIdx <= 12; chiefIdx++){
var $plate = $('#chief_{0}'.format(chiefIdx));
var $officerLevelText = $plate.find('.chiefLevelText');
var $name = $plate.find('.chiefName');
var turn = [];
for(var turnIdx=0;turnIdx<maxChiefTurn;turnIdx++){
var $turn = $plate.find('.turn{0}'.format(turnIdx));
var $turnTime = $turn.find('.chiefTurnTime');
var $turnPad = $turn.find('.chiefTurnPad');
var $turnText = $turn.find('.chiefTurnText');
turn.push({turnTime:$turnTime,turnPad:$turnPad,turnText:$turnText});
}
objTable[chiefIdx] = {
officerLevelText: $officerLevelText,
name: $name,
turn: turn
};
}
return objTable;
}
function clearChief(chiefIdx){
var $plate = $('#chief_{0}'.format(chiefIdx));
$plate.find('.chiefLevelText').html('-');
$plate.find('.chiefTurnTime, .chiefTurnText, .chiefName').html('&nbsp;');
}
function reloadTable(){
$.post({
url:'j_getChiefTurn.php',
dataType:'json',
}).then(function(data){
if(!data.result){
alert(data.reason);
return;
}
var turnTerm = data.turnTerm;
var tmpFilledChiefList = {};
if(data.isChief){
chiefTableObj.btns.css('visibility', 'visible');
}
else{
chiefTableObj.btns.css('visibility', 'hidden');
}
$.each(data.nationTurnBrief, function(chiefIdx, chiefInfo){
tmpFilledChiefList[chiefIdx] = true;
filledChiefList[chiefIdx] = true;
var plateObj = chiefTableObj[chiefIdx];
if(chiefInfo.name){
var $name = $('<span>{0}</span>'.format(chiefInfo.name));
var nameColor = getNpcColor(chiefInfo.npcType);
if(nameColor){
$name.css('color',nameColor);
}
plateObj.name.html($name);
}
else{
plateObj.name.html('');
}
plateObj.officerLevelText.text(chiefInfo.officerLevelText);
if(chiefInfo.turnTime){
var turnTimeObj = moment(chiefInfo.turnTime);
}
else{
var turnTimeObj = null;
}
var turnList = plateObj.turn;
$.each(chiefInfo.turn, function(turnIdx, turnText){
if(turnTimeObj){
turnList[turnIdx].turnTime.text(turnTimeObj.format('HH:mm'));
}
else{
turnList[turnIdx].turnTime.text('');
}
turnList[turnIdx].turnText.html(turnText).css('font-size', '13px');
var oWidth = turnList[turnIdx].turnPad.innerWidth();
var iWidth = turnList[turnIdx].turnText.outerWidth();
if(iWidth > oWidth * 0.95){
var newFontSize = 13 * oWidth / iWidth * 0.9;
turnList[turnIdx].turnText.css('font-size', '{0}px'.format(newFontSize));
}
if(turnTimeObj){
turnTimeObj = turnTimeObj.add(turnTerm, 'minute');
}
});
});
for(var idx=5;idx<=12;idx++){
if(idx in tmpFilledChiefList){
continue;
}
if(idx in filledChiefList){
clearChief(chiefIdx);
}
}
filledChiefList = tmpFilledChiefList;
}, errUnknown);
}
function reserveTurn(turnList, command){
console.log(turnList, command);
$.post({
url:'j_set_chief_command.php',
dataType:'json',
data:{
action:command,
turnList:turnList
}
}).then(function(data){
if(!data.result){
alert(data.reason);
}
reloadTable();
}, errUnknown);
}
function pushTurn(turnCnt){
$.post({
url:'j_chief_turn.php',
dataType:'json',
data:{
amount:turnCnt
}
}).then(function(data){
if(!data.result){
alert(data.reason);
}
reloadTable();
}, errUnknown);
}
jQuery(function($){
chiefTableObj= genChiefTableObj();
reloadTable();
$('#reloadTable').click(reloadTable);
$('#setCommand').click(function(){
var turnList = $('#chiefTurnSelector').val().map(function(v){return parseInt(v);});
var $command = $('#chiefCommandList option:selected');
if($command.data('reqarg')){
$.redirect(
"b_processing.php", {
command: $command.val(),
turnList: turnList.join('_'),
is_chief: true
}, "GET");
}
else{
reserveTurn(turnList, $command.val());
}
return false;
});
$('#turnPush').click(function(){
pushTurn(1);
});
$('#turnPull').click(function(){
pushTurn(-1);
});
})
+171 -103
View File
@@ -3,8 +3,8 @@
* @see https://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
* @param {string} string escape하고자 하는 문자열
* @returns {string}
*/
var escapeHtml = (function (string) {
*/
var escapeHtml = (function(string) {
var entityMap = {
'&': '&amp;',
'<': '&lt;',
@@ -32,58 +32,70 @@ function isInt(n) {
return +n === n && !(n % 1);
}
;(function(ns){
;
(function(ns) {
//https://gist.github.com/demouth/3217440
/**
* mb_strwidth
* @param String
* @return int
* @see http://php.net/manual/ja/function.mb-strwidth.php
*/
var mb_strwidth = function(str){
var i=0,l=str.length,c='',length=0;
for(;i<l;i++){
c=str.charCodeAt(i);
if(0x0000<=c&&c<=0x0019){
length += 0;
}else if(0x0020<=c&&c<=0x1FFF){
length += 1;
}else if(0x2000<=c&&c<=0xFF60){
length += 2;
}else if(0xFF61<=c&&c<=0xFF9F){
length += 1;
}else if(0xFFA0<=c){
length += 2;
}
}
return length;
};
/**
* mb_strimwidth
* @param String
* @param int
* @param int
* @param String
* @return String
* @see http://www.php.net/manual/ja/function.mb-strimwidth.php
*/
var mb_strimwidth = function(str,start,width,trimmarker){
if(typeof trimmarker === 'undefined') trimmarker='';
var trimmakerWidth = mb_strwidth(trimmarker),i=start,l=str.length,trimmedLength=0,trimmedStr='';
for(;i<l;i++){
var charCode=str.charCodeAt(i),c=str.charAt(i),charWidth=mb_strwidth(c),next=str.charAt(i+1),nextWidth=mb_strwidth(next);
trimmedLength += charWidth;
trimmedStr += c;
if(trimmedLength+trimmakerWidth+nextWidth>width){
trimmedStr += trimmarker;
break;
}
}
return trimmedStr;
};
ns.mb_strwidth = mb_strwidth;
ns.mb_strimwidth = mb_strimwidth;
/**
* mb_strwidth
* @param String
* @return int
* @see http://php.net/manual/ja/function.mb-strwidth.php
*/
var mb_strwidth = function(str) {
var i = 0,
l = str.length,
c = '',
length = 0;
for (; i < l; i++) {
c = str.charCodeAt(i);
if (0x0000 <= c && c <= 0x0019) {
length += 0;
} else if (0x0020 <= c && c <= 0x1FFF) {
length += 1;
} else if (0x2000 <= c && c <= 0xFF60) {
length += 2;
} else if (0xFF61 <= c && c <= 0xFF9F) {
length += 1;
} else if (0xFFA0 <= c) {
length += 2;
}
}
return length;
};
/**
* mb_strimwidth
* @param String
* @param int
* @param int
* @param String
* @return String
* @see http://www.php.net/manual/ja/function.mb-strimwidth.php
*/
var mb_strimwidth = function(str, start, width, trimmarker) {
if (typeof trimmarker === 'undefined') trimmarker = '';
var trimmakerWidth = mb_strwidth(trimmarker),
i = start,
l = str.length,
trimmedLength = 0,
trimmedStr = '';
for (; i < l; i++) {
var charCode = str.charCodeAt(i),
c = str.charAt(i),
charWidth = mb_strwidth(c),
next = str.charAt(i + 1),
nextWidth = mb_strwidth(next);
trimmedLength += charWidth;
trimmedStr += c;
if (trimmedLength + trimmakerWidth + nextWidth > width) {
trimmedStr += trimmarker;
break;
}
}
return trimmedStr;
};
ns.mb_strwidth = mb_strwidth;
ns.mb_strimwidth = mb_strimwidth;
})(window);
/**
@@ -93,7 +105,7 @@ function isInt(n) {
*/
function convertDictById(arr) {
var result = {};
arr.forEach(function (v, i) {
arr.forEach(function(v, i) {
result[v.id] = v;
});
return result;
@@ -106,7 +118,7 @@ function convertDictById(arr) {
*/
function convertSet(arr) {
var result = {};
arr.forEach(function (v) {
arr.forEach(function(v) {
result[v] = true;
});
return result;
@@ -115,10 +127,10 @@ function convertSet(arr) {
/**
* {0}, {1}, {2}형태로 포맷해주는 함수
*/
*/
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return this.replace(/{(\d+)}/g, function(match, number) {
return (typeof args[number] != 'undefined') ? args[number] : match;
});
};
@@ -134,12 +146,11 @@ function hexToRgb(hex) {
}
function isBrightColor(color){
function isBrightColor(color) {
color = hexToRgb(color);
if ((color.r*0.299 + color.g*0.587 + color.b*0.114) > 140){
if ((color.r * 0.299 + color.g * 0.587 + color.b * 0.114) > 140) {
return true;
}
else{
} else {
return false;
}
}
@@ -177,7 +188,7 @@ function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function linkifyStrWithOpt(text){
function linkifyStrWithOpt(text) {
return linkifyStr(text, {});
}
@@ -188,14 +199,14 @@ function linkifyStrWithOpt(text){
* @param {object} options
* @returns {string}
*/
var TemplateEngine = function (html, options) {
var TemplateEngine = function(html, options) {
var re = /<%(.+?)%>/g,
reExp = /(^( )?(var|if|for|else|switch|case|break|{|}|;))(.*)?/g,
code = 'with(obj) { var r=[];\n',
cursor = 0,
result,
match;
var add = function (line, js) {
var add = function(line, js) {
js ? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') :
(code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '');
return add;
@@ -208,82 +219,97 @@ var TemplateEngine = function (html, options) {
}
add(html.substr(cursor, html.length - cursor));
code = (code + 'return r.join(""); }').replace(/[\r\t\n]/g, ' ');
try { result = new Function('obj', code).apply(options, [options]); }
catch (err) { console.error("'" + err.message + "'", " in \n\nCode:\n", code, "\n"); }
try { result = new Function('obj', code).apply(options, [options]); } catch (err) { console.error("'" + err.message + "'", " in \n\nCode:\n", code, "\n"); }
return result;
}
function getIconPath(imgsvr, picture){
function getIconPath(imgsvr, picture) {
// ../d_shared/common_path.js 필요
if(!imgsvr){
return pathConfig.sharedIcon+'/'+picture;
}
else{
return pathConfig.root+'/d_pic/'+picture;
if (!imgsvr) {
return pathConfig.sharedIcon + '/' + picture;
} else {
return pathConfig.root + '/d_pic/' + picture;
}
}
function activeFlip($obj){
function activeFlip($obj) {
var $result;
if($obj === undefined){
if ($obj === undefined) {
$result = $('img[data-flip]');
}
else{
} else {
$result = $obj.find('img[data-flip]');
}
$result.each(function(){
$result.each(function() {
activeFlipItem($(this));
});
}
function activeFlipItem($img){
function combineObject(item, columnList) {
var newItem = {};
for (var columnIdx in columnList) {
var columnName = columnList[columnIdx];
newItem[columnName] = item[columnIdx];
}
return newItem;
}
function combineArray(array, columnList) {
var result = [];
for (var key in array) {
var item = array[key];
result[key] = combineObject(item, columnList);
}
return result;
}
function activeFlipItem($img) {
var imageList = [];
imageList.push($img.attr('src'));
$.each($img.data('flip').split(','), function(idx, value){
$.each($img.data('flip').split(','), function(idx, value) {
var value = $.trim(value);
if(!value){
if (!value) {
return true;
}
imageList.push(value);
});
if(imageList.length <= 1){
if (imageList.length <= 1) {
return;
}
$img.data('computed_flip_array', imageList);
$img.data('computed_flip_idx', 0);
$img.click(function(){
$img.click(function() {
var arr = $img.data('computed_flip_array');
var idx = $img.data('computed_flip_idx');
idx = (idx + 1)%(arr.length);
idx = (idx + 1) % (arr.length);
$img.attr('src', arr[idx]);
$img.data('computed_flip_idx', idx);
});
$img.css('cursor','pointer');
$img.css('cursor', 'pointer');
}
jQuery(function($){
$('.obj_tooltip').mouseover(function(){
jQuery(function($) {
$('.obj_tooltip').mouseover(function() {
var $objTooltip = $(this);
if($objTooltip.data('setObjTooltip')){
if ($objTooltip.data('setObjTooltip')) {
return true;
}
var tooltipClassText = $objTooltip.data('tooltip-class');
if(!tooltipClassText){
if (!tooltipClassText) {
tooltipClassText = '';
}
var template = '<div class="tooltip {0}" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>'
.format(tooltipClassText);
$objTooltip.tooltip({
title:function(){
title: function() {
return $.trim($(this).find('.tooltiptext').html());
},
template:template,
html:true
template: template,
html: true
}).tooltip('show');
$objTooltip.data('setObjTooltip', true);
@@ -297,21 +323,21 @@ jQuery(function($){
activeFlip();
var customCSS = localStorage.getItem('sam_customCSS');
if(customCSS){
if (customCSS) {
var $style = $('<style type="text/css"></style>');
$style.text(customCSS);
$style.text(customCSS);
$style.appendTo($('head'));
}
});
function errUnknown(){
function errUnknown() {
alert('작업을 실패했습니다.');
}
function errUnknownToast(){
function errUnknownToast() {
$.toast({
title: '에러!',
content: '작업을 실패했습니다.',
@@ -320,8 +346,8 @@ function errUnknownToast(){
});
}
function quickReject(errMsg){
if(errMsg === undefined){
function quickReject(errMsg) {
if (errMsg === undefined) {
errMsg = '작업을 실패했습니다.';
}
var deferred = $.Deferred();
@@ -329,8 +355,8 @@ function quickReject(errMsg){
return deferred.promise();
}
function nl2br(text){
return text.replace(/\n/g,"<br>");
function nl2br(text) {
return text.replace(/\n/g, "<br>");
}
/*
function br2nl (text) {
@@ -338,12 +364,54 @@ function br2nl (text) {
}
*/
function getNpcColor(npcType){
if(npcType >= 2){
function getNpcColor(npcType) {
if (npcType >= 2) {
return 'cyan';
}
if(npcType == 1){
if (npcType == 1) {
return 'skyblue';
}
return null;
}
function initTooltip($obj) {
if ($obj === undefined) {
$obj = $('.obj_tooltip');
} else if (!$obj.hasClass('obj_tooltip')) {
$obj = $obj.find('.obj_tooltip');
}
console.log($obj);
$obj.each(function() {
$target = $(this);
if ($target.data('installHandler')) {
return true;
}
$target.data('installHandler', true);
$target.mouseover(function() {
var $objTooltip = $(this);
if ($objTooltip.data('setObjTooltip')) {
return true;
}
var tooltipClassText = $objTooltip.data('tooltip-class');
if (!tooltipClassText) {
tooltipClassText = '';
}
var template = '<div class="tooltip {0}" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>'
.format(tooltipClassText);
$objTooltip.tooltip({
title: function() {
return $.trim($(this).find('.tooltiptext').html());
},
template: template,
html: true
}).tooltip('show');
$objTooltip.data('setObjTooltip', true);
});
});
}
+16 -16
View File
@@ -1,17 +1,17 @@
$(function(){
var $target = $("#destCityID");
reloadWorldMap({
isDetailMap:false,
clickableAll:true,
neutralView:true,
useCachedMap:true,
selectCallback:function(city){
var currVal = $target.val();
$target.val(city.id);
if($target.val() === null){
$target.val(currVal);
}
return false;
}
});
$(function() {
var $target = $("#destCityID");
reloadWorldMap({
isDetailMap: false,
clickableAll: true,
neutralView: true,
useCachedMap: true,
selectCallback: function(city) {
var currVal = $target.val();
$target.val(city.id).trigger("change");
if ($target.val() === null) {
$target.val(currVal).trigger("change");
}
return false;
}
});
});
+16 -16
View File
@@ -1,17 +1,17 @@
$(function(){
var $target = $("#destNationID");
reloadWorldMap({
isDetailMap:false,
clickableAll:true,
neutralView:true,
useCachedMap:true,
selectCallback:function(city){
var currVal = $target.val();
$target.val(city.nationId);
if($target.val() === null){
$target.val(currVal);
}
return false;
}
});
$(function() {
var $target = $("#destNationID");
reloadWorldMap({
isDetailMap: false,
clickableAll: true,
neutralView: true,
useCachedMap: true,
selectCallback: function(city) {
var currVal = $target.val();
$target.val(city.nationId).trigger("change");
if ($target.val() === null) {
$target.val(currVal).trigger("change");
}
return false;
}
});
});
+898 -898
View File
@@ -1,899 +1,899 @@
$(function() {
var cityList = {};
var userList = {};
var cityGroupOrder = ['하북','중원','서북','서촉','남중','초','오월','동이'];
var city규모 = {:1,:2,:3,:4,:5,:6,:7,:8};
window.cityList = cityList;
window.userList = userList;
var basicPath = document.location.pathname;
basicPath = basicPath.substring(0, basicPath.lastIndexOf('/'))+'/';
var mergeSort = function(arr,cmpFunc){
if(typeof cmpFunc == "undefined"){
cmpFunc = function(a,b){
if(a<b) return -1;
if(a>b) return 1;
return 0;
}
}
var merge = function(left,right){
var retVal=[];
var leftIdx=0;
var rightIdx=0;
while(leftIdx<left.length && rightIdx<right.length){
var cmpVal = cmpFunc(left[leftIdx],right[rightIdx]);
if(cmpVal<=0){
retVal.push(left[leftIdx]);
leftIdx++;
}
else{
retVal.push(right[rightIdx]);
rightIdx++;
}
}
retVal = retVal.concat(left.slice(leftIdx)).concat(right.slice(rightIdx))
return retVal;
};
var _mergeSort = function(arr){
if(arr.length<2){
return arr;
}
var middle = Math.floor(arr.length/2);
var left = arr.slice(0,middle);
var right = arr.slice(middle);
return merge(_mergeSort(left),_mergeSort(right));
};
return _mergeSort(arr);
};
window.mergeSort = mergeSort;
var extDutyWindow = function(userInfo){
window.currUser = userInfo;
//도시 순서 재구성
var subCityGroupList = {};
var subCityList = {};
var tmpOldVal = 0;
//var callCity = function(num){console.log('city no.'+num+' is clicked!')};
if($('#ext_win').length==0){
var $win = $('<div id="ext_win" style="padding:0;" title="관직 임명"><table style="padding:0;margin:0;" cellspacing="0" cellpadding="0" border="0"><tr><td width="700px" style="padding:0;"><iframe id="in_frame" src="map.php?type=1&amp;graphic=1" width="700" height="520" frameborder="0" marginwidth="0" marginheight="0" topmargin="0" scrolling="no"></iframe></td>'+
'<td width="305px" style="padding:0;vertical-align:top;height:520px;"><div style="height:520px;width:305px;overflow-y:scroll;overflow-x:hidden;">'+
'<table id="inner_table"><thead><tr><th width="35">도시</th><th width="85">태수</th><th width="85">군사</th><th width="85">종사</th></tr></thead><tbody class="content">'+
'</tbody></table></div></td></tr></table>'+
'<form name="form1" id="fake_form"><span id="user_name"></span> : <select name="double" id="city_select"></select>'+
'<div id="duty_radio" style="display:inline;">'+
'<input type="radio" id="duty_type1" value="4" name="duty_radio"><label for="duty_type1">태수</label>'+
'<input type="radio" id="duty_type2" value="3" name="duty_radio"><label for="duty_type2">군사</label>'+
'<input type="radio" id="duty_type3" value="2" name="duty_radio"><label for="duty_type3">종사</label>'+
'</div></form></div>');
$win.hide();
$win.css('font-size','9pt');
$('#fake_form').css('display','inline');
$('body').append($win);
$('#inner_table').attr('border','1').attr('cellspacing',"0").attr('cellpadding',"0")
.attr('bordercolordark',"gray").attr('bordercolorlight',"black").attr('align','center')
.css('font-size','13px').css('width','290px');
$('#inner_table thead tr');
$('#fake_form').submit(function(){
return false;
});
$('#in_frame').load(function(){
$('#in_frame').contents().find('div').click(function(){$('#city_select').change();});
});
$("#duty_radio").buttonset();
var $city_select = $('#city_select');
$city_select.css('color','white').css('background-color','black');
$city_select.change(function(event){
if($city_select.val()==null){
$city_select.val(tmpOldVal);
return false;
}
if($city_select.val() == tmpOldVal){
return false;
}
tmpOldVal = $city_select.val();
//console.log(tmpOldVal);
var newInfo = subCityList[tmpOldVal];
var cityInfo = newInfo.city;
var p태수 = cityInfo.p태수 && currUser.p태수;
var p군사 = cityInfo.p군사 && currUser.p군사;
var p종사 = cityInfo.p종사 && currUser.p종사;
//console.log(p태수,p군사,p종사);
$('#duty_type1').button({disabled:!p태수});
$('#duty_type2').button({disabled:!p군사});
$('#duty_type3').button({disabled:!p종사});
var $태수 = cityInfo.$태수;
var $군사 = cityInfo.$군사;
var $종사 = cityInfo.$종사;
return true;
});
$win.dialog({
autoOpen:false,
width:1005,
height:680,
buttons:{
"임명":function(){
//console.log("임명!");
var $checked = $('#duty_radio :radio:checked');
if($checked.length==0 || $checked.attr('disabled')=='disabled'){
alert('직책을 선택해주세요!');
return false;
}
var type = $checked.attr('value');
var text = $checked.next().text();
var userVal = currUser.val;
var userName = currUser.name;
var cityVal = $city_select.val();
var cityInfo = subCityList[cityVal].city;
$.post(basicPath+'j_myBossInfo.php',{
destCityID:cityVal,
destGeneralID:userVal,
officerLevel:type,
action:'임명'
},function(rawData){
cityInfo['p'+text]=false;
var $target = cityInfo.users.find('.mode_'+type);
$target.prop('disabled',true);
$target.css('background','transparent');
$target.css('border','0');
$target.css('color','');
cityInfo['$'+text].html(userName);
$win.dialog("close");
});
},
"닫기":function(){
$win.dialog("close");
}
}
});
//console.log($win.parent());
$win.parent().css('font-size','10pt');
}
$('#ext_win').dialog("close").dialog( "option", "position", { my: "center top", at: "center bottom", of: userInfo.$user} );
var $innerContent = $('#inner_table .content');
$innerContent.html('');
$("#user_name").html(userInfo.name+'['+userInfo.city+']');
$('#city_select').html('');
$.each(cityList,function(idx,cityInfo){
var 지역 = cityInfo.지역;
var p태수 = cityInfo.p태수 && currUser.p태수;
var p군사 = cityInfo.p군사 && currUser.p군사;
var p종사 = cityInfo.p종사 && currUser.p종사;
var newInfo = {
지역 : 지역,
규모 : cityInfo.규모,
이름 : cityInfo.이름,
val : cityInfo.val,
city : cityInfo,
p태수 : p태수,
p군사 : p군사,
p종사 : p종사
};
//console.log(newInfo);
if(p태수 || p군사 || p종사){
if(typeof subCityGroupList[지역] == 'undefined'){
subCityGroupList[지역] = [];
}
subCityGroupList[지역].push(newInfo);
subCityList[cityInfo.val] = newInfo;
}
});
$.each(cityGroupOrder,function(idx,groupName){
if(typeof subCityGroupList[groupName] == 'undefined'){
return true;
}
var subList = subCityGroupList[groupName];
var $group = $('<tr><td colspan="4" style="color:skyblue;">【 '+groupName+' 】</td></tr>');
$innerContent.append($group);
subList.sort(function(a,b){
var cmp규모 = city규모[a.규모] - city규모[b.규모];
if(cmp규모 != 0) return cmp규모;
return a.이름.localeCompare(b.이름);
});
var $optgroup = $('<optgroup label=" 【 '+groupName+' 】 " style="color:skyblue;"></optgroup>');
$.each(subList,function(idx,newInfo){
$optgroup.append('<option value="'+newInfo.val+'" style="color:white;">'+newInfo.이름+'</option>');
var cityInfo = newInfo.city;
var $city = $('<tr><td>'+newInfo.이름+'</td></tr>');
var $태수 = cityInfo.$태수.clone();
$city.append($태수);
if(!newInfo.p태수){
$태수.css('color','red');
}
else{
$태수.click(function(){
$('#duty_radio :radio:eq(0)').attr('checked','checked');
$('#duty_radio :radio').button('refresh');
}).css('cursor','pointer');
}
var $군사 = cityInfo.$군사.clone();
$city.append($군사);
if(!newInfo.p군사)$군사.css('color','red');
else{
$군사.click(function(){
$('#duty_radio :radio:eq(1)').attr('checked','checked');
$('#duty_radio :radio').button('refresh');
}).css('cursor','pointer');
}
var $종사 = cityInfo.$종사.clone();
$city.append($종사);
if(!newInfo.p종사)$종사.css('color','red');
else{
$종사.click(function(){
$('#duty_radio :radio:eq(2)').attr('checked','checked');
$('#duty_radio :radio').button('refresh');
}).css('cursor','pointer');
}
$innerContent.append($city);
$city.click(function(){
$('#city_select').val(newInfo.val).change();
});
});
$('#city_select').append($optgroup);
});
tmpOldVal = $('#city_select').val();
$('#city_select').change();
$('#ext_win').dialog("open");
};
var loadDuty = function(){
try{
$('.for_duty').remove();
$.get(basicPath+'b_myBossInfo.php',function(rawData){
$html = $(rawData);
//window.$html = $html;
var cnt =0;
var $tmpTable = $html.filter('#officer_list').eq(0);
$selects = $tmpTable.find("select");
if($selects.length == 0){
alert("수뇌가 아닙니다!");
return false;
}
var setUserAvailable = function($userList,typeName){
$userList.each(function(idx){
var $this = $(this);
var val = $this.val();
var name = $.trim($this.text());
for(var i=name.length-1;i>0;i--){
if(name[i]=='【'){
name = $.trim(name.substr(0,i));
break;
}
}
if(val == '0'){
return true;
}
if(typeof userList[name] != 'undefined'){
userList[name].val = val;
userList[name][typeName] = true;
}
});
};
var setCityAvailiable = function($cityList,typeName){
$cityList.each(function(idx){
var $this = $(this);
var val = $.trim($this.val());
var name = $.trim($this.text());
cityList[name].val = val;
cityList[name][typeName] = true;
});
}
$.each(cityList,function(idx,cityInfo){
cityInfo.p태수=false;
cityInfo.p군사=false;
cityInfo.p종사=false;
});
$.each(userList,function(idx,userInfo){
userInfo.p태수=false;
userInfo.p군사=false;
userInfo.p종사=false;
});
setUserAvailable($selects.eq(1).find("option"),"p태수");
setUserAvailable($selects.eq(3).find("option"),"p군사");
setUserAvailable($selects.eq(5).find("option"),"p종사");
setCityAvailiable($selects.eq(0).find("option"),"p태수");
setCityAvailiable($selects.eq(2).find("option"),"p군사");
setCityAvailiable($selects.eq(4).find("option"),"p종사");
$.each(cityList,function(idx,cityInfo){
//console.log(cityInfo.users.children());
cityInfo.users.children().each(function(idx){
//console.log(this);
var $this = $(this);
var username = $this.data('username');
var userInfo = userList[username];
if(!userInfo){
return true;
}
if(userInfo.val == '-1'){
return true;
}
$name = $this.find('.nameplate');
$name.append('<br class="for_duty">');
var addBtn=function($name,cityInfo,userInfo,type,text,warn){
var enabled = cityInfo['p'+text]&&userInfo['p'+text];
var cityVal = cityInfo.val;
var $btn = $('<button type="button">'+text.substr(0,1)+'</button>');
$btn.addClass('mode_'+type);
$btn.addClass('for_duty');
if(!enabled){
$btn.prop('disabled',true);
$btn.css('background','transparent');
$btn.css('border','0');
}
else{
if(userInfo.is수뇌){
$btn.css('color','red');
}
}
$btn.css('padding','1px 4px');
$btn.css('margin','0');
$btn.click(function(){
if(userInfo.is수뇌){
if(!confirm('수뇌입니다. 임명할까요?')){
return false;
}
}
$.post(basicPath+'j_myBossInfo.php',{
destCityID:cityVal,
destGeneralID:userInfo.val,
officerLevel:type,
action:'임명'
},function(rawData){
cityInfo['p'+text]=false;
var $target = cityInfo.users.find('.mode_'+type);
$target.prop('disabled',true);
$target.css('background','transparent');
$target.css('border','0');
$target.css('color','');
cityInfo['$'+text].html(userInfo.name);
});
});
//console.log($btn);
$name.append($btn);
};
addBtn($name,cityInfo,userInfo,4,'태수');
addBtn($name,cityInfo,userInfo,3,'군사');
addBtn($name,cityInfo,userInfo,2,'종사');
//특수 버튼!
if(userInfo.p태수||userInfo.p군사||userInfo.p종사){
var $btn = $('<button type="button">...</button>');
$btn.addClass('for_duty');
if(userInfo.is수뇌){
$btn.css('color','red');
}
$btn.css('padding','1px 4px');
$btn.css('margin','0');
$btn.click(function(){
if(userInfo.is수뇌){
if(!confirm('수뇌입니다. 임명할까요?')){
return false;
}
}
extDutyWindow(userInfo);
});
$btn.css('border','solid 1px Chocolate').css('background-color','#400000').css('margin-left','4px');
$btn.css('line-hight','20px').css('color','GhostWhite').css('padding','2px 2px').css('height','18px').css('line-height','8px');
//$name.append($btn);
}
});
});
});
}
catch(a){
console.log(a);
}
return false;
};
var loadUser = function(){
$.each(cityList,function(idx,val){
if(typeof val.users == "undefined"){
val.obj.append('<tr><td colspan="12"><table align="center" class="tb_layout cityUser bg0">'+
'<thead><tr>'+
'<td width="100" align="center" class="bg1">이 름</td><td width="100" align="center" class="bg1">통무지</td><td width="100" align="center" class="bg1">부 대</td><td width="60" align="center" class="bg1">자 금</td>'+
'<td width="60" align="center" class="bg1">군 량</td><td width="30" align="center" class="bg1">守</td><td width="60" align="center" class="bg1">병 종</td>'+
'<td width="60" align="center" class="bg1">병 사</td><td width="50" align="center" class="bg1">훈련</td><td width="50" align="center" class="bg1">사기</td><td width="150" align="center" class="bg1">명 령</td>'+
'<td width="60" align="center" class="bg1">삭턴</td><td width="60" align="center" class="bg1">턴</td>'+
'</tr></thead>'+
'<tbody class="cityUserBody"></tbody></table></td></tr>');
val.users = val.obj.find(".cityUserBody");
}
else{
val.users.html("");
}
});
$.get(basicPath+'b_genList.php',function(rawData){
var cnt =0;
var $helper = $('#helper_genlist');
$helper.html('').append($.parseHTML(rawData));
var tmpUsers = $('#general_list tbody tr');
tmpUsers.each(function(idx){
var $this = $(this);
var $city = $this.children('.i_city');
$city.remove();
var cityName = $.trim($city.text());
var $name = $this.children('.i_name');
$name.addClass('nameplate');
var name = $name.find('.t_name').text();
var $work = $this.children('.i_action');
var cityInfo = cityList[cityName];
if(typeof cityInfo == 'undefined'){
return true;
}
if(cityInfo.warn주민)$work.html($work.html().split('정착 장려').join('<span style="color:yellow;">정착 장려</span>'));
if(cityInfo.warn농업)$work.html($work.html().split('농지 개간').join('<span style="color:yellow;">농지 개간</span>'));
if(cityInfo.warn상업)$work.html($work.html().split('상업 투자').join('<span style="color:yellow;">상업 투자</span>'));
if(cityInfo.warn치안)$work.html($work.html().split('치안 강화').join('<span style="color:yellow;">치안 강화</span>'));
if(cityInfo.warn수비)$work.html($work.html().split('수비 강화').join('<span style="color:yellow;">수비 강화</span>'));
if(cityInfo.warn성벽)$work.html($work.html().split('성벽 보수').join('<span style="color:yellow;">성벽 보수</span>'));
var $stat = $this.children('.i_stat');
var stat = $stat.text();
var is수뇌 = stat.indexOf('+')>=0;
$this.data('username',name);
if(cityList[cityName].$태수.text() == name){
cityList[cityName].$태수.css('color','lightgreen');
}
if(cityList[cityName].$군사.text() == name){
cityList[cityName].$군사.css('color','lightgreen');
}
if(cityList[cityName].$종사.text() == name){
cityList[cityName].$종사.css('color','lightgreen');
}
userList[name]={
$city:cityInfo,
city:cityName,
$user:$this,
name:name,
val:'-1',
p태수:false,
p군사:false,
p종사:false,
is수뇌:is수뇌
};
if(cityList[cityName]){
cityList[cityName].users.append($this);
}
});
});
if($("#loadDutyBtn").length == 0){
var $onBossList = $('<button id="loadDutyBtn">인사부 연동</button>');
$onBossList.click(function(){
loadDuty();
return false;
});
$('form').append($onBossList);
}
$('#by_users').show();
};
var mainFunc = function(){
//대상 추출
window.cityList = {};
window.userList = {};
$("form").each(function(){
var $this = $(this);
$this.attr('name','p'+$this.attr('name'));
});
$("table").each(function(idx,val){
$this = $(this);
if($this.attr('class')=='tb_layout bg2'){
$this.addClass('cityInfo');
}
else{
return true;
}
window.$tmpTable = $this;
var cityInfo = {};
//이름 추출
{
var titleText = $this.find('tr:eq(0)>td:eq(0)').text();
var loc0 = titleText.indexOf("【");
var loc1 = titleText.indexOf("|");
var loc2 = titleText.indexOf("】");
var cityLoc = $.trim(titleText.substring(loc0+1,loc1));
var citySize = $.trim(titleText.substring(loc1+1,loc2));
var cityName = $.trim(titleText.substring(loc2+1));
cityName = cityName.replace("[","");
cityName = cityName.replace("]","");
$this.data('cityname',cityName);
cityInfo.지역 = cityLoc;
cityInfo.규모 = citySize;
cityInfo.이름 = cityName;
cityInfo.val = '-1';
cityInfo.p태수 = false;
cityInfo.p군사 = false;
cityInfo.p종사 = false;
}
//주민, 농상치성수
{
var $baseTr = $this.find('tr:eq(1)');
cityInfo.$주민 = $baseTr.find('td:eq(1)');
cityInfo.$농업 = $baseTr.find('td:eq(3)');
cityInfo.$상업 = $baseTr.find('td:eq(5)');
cityInfo.$치안 = $baseTr.find('td:eq(7)');
cityInfo.$수비 = $baseTr.find('td:eq(9)');
cityInfo.$성벽 = $baseTr.find('td:eq(11)');
var tmpVal;
tmpVal = cityInfo.$주민.text().split('/');
cityInfo.주민 = parseInt(tmpVal[0]);
cityInfo.max주민 = parseInt(tmpVal[1]);
tmpVal = cityInfo.$농업.text().split('/');
cityInfo.농업 = parseInt(tmpVal[0]);
cityInfo.max농업 = parseInt(tmpVal[1]);
tmpVal = cityInfo.$상업.text().split('/');
cityInfo.상업 = parseInt(tmpVal[0]);
cityInfo.max상업 = parseInt(tmpVal[1]);
tmpVal = cityInfo.$치안.text().split('/');
cityInfo.치안 = parseInt(tmpVal[0]);
cityInfo.max치안 = parseInt(tmpVal[1]);
tmpVal = cityInfo.$수비.text().split('/');
cityInfo.수비 = parseInt(tmpVal[0]);
cityInfo.max수비 = parseInt(tmpVal[1]);
tmpVal = cityInfo.$성벽.text().split('/');
cityInfo.성벽 = parseInt(tmpVal[0]);
cityInfo.max성벽 = parseInt(tmpVal[1]);
if (cityInfo.주민>cityInfo.max주민*0.9){ cityInfo.$주민.css('color','lightgreen');}
else if (cityInfo.주민>cityInfo.max주민*0.7){ cityInfo.$주민.css('color','yellow');}
else { cityInfo.$주민.css('color','orangered');}
if (cityInfo.농업>cityInfo.max농업*0.8){ cityInfo.$농업.css('color','lightgreen');}
else if (cityInfo.농업>cityInfo.max농업*0.4){ cityInfo.$농업.css('color','yellow');}
else { cityInfo.$농업.css('color','orangered');}
if (cityInfo.상업>cityInfo.max상업*0.8){ cityInfo.$상업.css('color','lightgreen');}
else if (cityInfo.상업>cityInfo.max상업*0.4){ cityInfo.$상업.css('color','yellow');}
else { cityInfo.$상업.css('color','orangered');}
if (cityInfo.치안>cityInfo.max치안*0.8){ cityInfo.$치안.css('color','lightgreen');}
else if (cityInfo.치안>cityInfo.max치안*0.4){ cityInfo.$치안.css('color','yellow');}
else { cityInfo.$치안.css('color','orangered');}
if (cityInfo.수비>cityInfo.max수비*0.6){ cityInfo.$수비.css('color','lightgreen');}
else if (cityInfo.수비>cityInfo.max수비*0.3){ cityInfo.$수비.css('color','yellow');}
else { cityInfo.$수비.css('color','orangered');}
if (cityInfo.성벽>cityInfo.max성벽*0.6){ cityInfo.$성벽.css('color','lightgreen');}
else if (cityInfo.성벽>cityInfo.max성벽*0.3){ cityInfo.$성벽.css('color','yellow');}
else { cityInfo.$성벽.css('color','orangered');}
cityInfo.remain주민 = cityInfo.주민-cityInfo.max주민;
cityInfo.remain농업 = cityInfo.농업-cityInfo.max농업;
cityInfo.remain상업 = cityInfo.상업-cityInfo.max상업;
cityInfo.remain치안 = cityInfo.치안-cityInfo.max치안;
cityInfo.remain수비 = cityInfo.수비-cityInfo.max수비;
cityInfo.remain성벽 = cityInfo.성벽-cityInfo.max성벽;
cityInfo.warn주민 = false;
cityInfo.warn농업 = false;
cityInfo.warn상업 = false;
cityInfo.warn치안 = false;
cityInfo.warn수비 = false;
cityInfo.warn성벽 = false;
if(cityInfo.remain주민 > -10*2000) cityInfo.warn주민 = true;
if(cityInfo.주민 > 0.92*cityInfo.max주민) cityInfo.warn주민 = true;
if(cityInfo.remain농업 > -10*100) cityInfo.warn농업 = true;
if(cityInfo.remain상업 > -10*100) cityInfo.warn상업 = true;
if(cityInfo.remain치안 > -10*100) cityInfo.warn치안 = true;
if(cityInfo.remain수비 > -10*70) cityInfo.warn수비 = true;
if(cityInfo.remain성벽 > -10*70) cityInfo.warn성벽 = true;
if(cityInfo.warn농업) cityInfo.$농업.append('<span class="remain" style="color:yellow;">['+cityInfo.remain농업+']</span>');
if(cityInfo.warn상업) cityInfo.$상업.append('<span class="remain" style="color:yellow;">['+cityInfo.remain상업+']</span>');
if(cityInfo.warn치안) cityInfo.$치안.append('<span class="remain" style="color:yellow;">['+cityInfo.remain치안+']</span>');
if(cityInfo.warn수비) cityInfo.$수비.append('<span class="remain" style="color:yellow;">['+cityInfo.remain수비+']</span>');
if(cityInfo.warn성벽) cityInfo.$성벽.append('<span class="remain" style="color:yellow;">['+cityInfo.remain성벽+']</span>');
}
//태수,군사,종사
{
var $baseTr = $this.find('tr:eq(2)');
cityInfo.$태수 = $baseTr.find('td:eq(7)');
cityInfo.$군사 = $baseTr.find('td:eq(9)');
cityInfo.$종사 = $baseTr.find('td:eq(11)');
}
//기타
{
cityInfo.userCnt = $this.find('tr:eq(3) td:eq(1)').text().split(',').length -1;
}
cityInfo.obj = $this;
cityList[cityInfo.이름] = cityInfo;
});
var $onGenList = $('<button type="button">암행부 연동</button>');
$onGenList.click(function(){
loadUser();
return false;
});
$('form').append($onGenList);
$('table:eq(0) tr:last').after('<tr><td id="sort_more"></td></tr>');
$sort_more = $('#sort_more');
$sort_more.html('재 정렬 순서 :');
var sortIt = function(callback){
var arCity = [];
$('.cityInfo').each(function(){
var $this = $(this);
var cityName = $this.data('cityname');
var cityInfo = cityList[cityName];
arCity.push(cityInfo);
});
arCity = mergeSort(arCity,callback);
//console.log(arCity);
var $anchor = $('.anchor');
//console.log($anchor);
$('body > br').remove();
$('.cityInfo').detach();
$.each(arCity,function(idx,val){
$anchor.before('<br>');
$anchor.before(val.obj);
});
$anchor.before('<br>');
};
var $btn;
$btn = $('<button type="button">도시명</button>').click(function(){
sortIt(function(a,b){
return a.이름.localeCompare(b.이름);
});
});
$sort_more.append($btn);
$btn = $('<button type="button">인구율</button>').click(function(){
sortIt(function(a,b){
return 1.0*a.주민/a.max주민 - 1.0*b.주민/b.max주민;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">남은 주민</button>').click(function(){
sortIt(function(a,b){
return a.remain주민 - b.remain주민;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">남은 농업</button>').click(function(){
sortIt(function(a,b){
return a.remain농업 - b.remain농업;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">남은 상업</button>').click(function(){
sortIt(function(a,b){
return a.remain상업 - b.remain상업;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">남은 치안</button>').click(function(){
sortIt(function(a,b){
return a.remain치안 - b.remain치안;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">남은 수비</button>').click(function(){
sortIt(function(a,b){
return a.remain수비 - b.remain수비;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">남은 성벽</button>').click(function(){
sortIt(function(a,b){
return a.remain성벽 - b.remain성벽;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">배치 장수 수</button>').click(function(){
sortIt(function(a,b){
return b.userCnt - a.userCnt;
});
});
$sort_more.append($btn);
};
mainFunc();
$(function() {
var cityList = {};
var userList = {};
var cityGroupOrder = ['하북','중원','서북','서촉','남중','초','오월','동이'];
var city규모 = {:1,:2,:3,:4,:5,:6,:7,:8};
window.cityList = cityList;
window.userList = userList;
var basicPath = document.location.pathname;
basicPath = basicPath.substring(0, basicPath.lastIndexOf('/'))+'/';
var mergeSort = function(arr,cmpFunc){
if(typeof cmpFunc == "undefined"){
cmpFunc = function(a,b){
if(a<b) return -1;
if(a>b) return 1;
return 0;
}
}
var merge = function(left,right){
var retVal=[];
var leftIdx=0;
var rightIdx=0;
while(leftIdx<left.length && rightIdx<right.length){
var cmpVal = cmpFunc(left[leftIdx],right[rightIdx]);
if(cmpVal<=0){
retVal.push(left[leftIdx]);
leftIdx++;
}
else{
retVal.push(right[rightIdx]);
rightIdx++;
}
}
retVal = retVal.concat(left.slice(leftIdx)).concat(right.slice(rightIdx))
return retVal;
};
var _mergeSort = function(arr){
if(arr.length<2){
return arr;
}
var middle = Math.floor(arr.length/2);
var left = arr.slice(0,middle);
var right = arr.slice(middle);
return merge(_mergeSort(left),_mergeSort(right));
};
return _mergeSort(arr);
};
window.mergeSort = mergeSort;
var extDutyWindow = function(userInfo){
window.currUser = userInfo;
//도시 순서 재구성
var subCityGroupList = {};
var subCityList = {};
var tmpOldVal = 0;
//var callCity = function(num){console.log('city no.'+num+' is clicked!')};
if($('#ext_win').length==0){
var $win = $('<div id="ext_win" style="padding:0;" title="관직 임명"><table style="padding:0;margin:0;" cellspacing="0" cellpadding="0" border="0"><tr><td width="700px" style="padding:0;"><iframe id="in_frame" src="map.php?type=1&amp;graphic=1" width="700" height="520" frameborder="0" marginwidth="0" marginheight="0" topmargin="0" scrolling="no"></iframe></td>'+
'<td width="305px" style="padding:0;vertical-align:top;height:520px;"><div style="height:520px;width:305px;overflow-y:scroll;overflow-x:hidden;">'+
'<table id="inner_table"><thead><tr><th width="35">도시</th><th width="85">태수</th><th width="85">군사</th><th width="85">종사</th></tr></thead><tbody class="content">'+
'</tbody></table></div></td></tr></table>'+
'<form name="form1" id="fake_form"><span id="user_name"></span> : <select name="double" id="city_select"></select>'+
'<div id="duty_radio" style="display:inline;">'+
'<input type="radio" id="duty_type1" value="4" name="duty_radio"><label for="duty_type1">태수</label>'+
'<input type="radio" id="duty_type2" value="3" name="duty_radio"><label for="duty_type2">군사</label>'+
'<input type="radio" id="duty_type3" value="2" name="duty_radio"><label for="duty_type3">종사</label>'+
'</div></form></div>');
$win.hide();
$win.css('font-size','9pt');
$('#fake_form').css('display','inline');
$('body').append($win);
$('#inner_table').attr('border','1').attr('cellspacing',"0").attr('cellpadding',"0")
.attr('bordercolordark',"gray").attr('bordercolorlight',"black").attr('align','center')
.css('font-size','13px').css('width','290px');
$('#inner_table thead tr');
$('#fake_form').submit(function(){
return false;
});
$('#in_frame').load(function(){
$('#in_frame').contents().find('div').click(function(){$('#city_select').change();});
});
$("#duty_radio").buttonset();
var $city_select = $('#city_select');
$city_select.css('color','white').css('background-color','black');
$city_select.change(function(event){
if($city_select.val()==null){
$city_select.val(tmpOldVal);
return false;
}
if($city_select.val() == tmpOldVal){
return false;
}
tmpOldVal = $city_select.val();
//console.log(tmpOldVal);
var newInfo = subCityList[tmpOldVal];
var cityInfo = newInfo.city;
var p태수 = cityInfo.p태수 && currUser.p태수;
var p군사 = cityInfo.p군사 && currUser.p군사;
var p종사 = cityInfo.p종사 && currUser.p종사;
//console.log(p태수,p군사,p종사);
$('#duty_type1').button({disabled:!p태수});
$('#duty_type2').button({disabled:!p군사});
$('#duty_type3').button({disabled:!p종사});
var $태수 = cityInfo.$태수;
var $군사 = cityInfo.$군사;
var $종사 = cityInfo.$종사;
return true;
});
$win.dialog({
autoOpen:false,
width:1005,
height:680,
buttons:{
"임명":function(){
//console.log("임명!");
var $checked = $('#duty_radio :radio:checked');
if($checked.length==0 || $checked.attr('disabled')=='disabled'){
alert('직책을 선택해주세요!');
return false;
}
var type = $checked.attr('value');
var text = $checked.next().text();
var userVal = currUser.val;
var userName = currUser.name;
var cityVal = $city_select.val();
var cityInfo = subCityList[cityVal].city;
$.post(basicPath+'j_myBossInfo.php',{
destCityID:cityVal,
destGeneralID:userVal,
officerLevel:type,
action:'임명'
},function(rawData){
cityInfo['p'+text]=false;
var $target = cityInfo.users.find('.mode_'+type);
$target.prop('disabled',true);
$target.css('background','transparent');
$target.css('border','0');
$target.css('color','');
cityInfo['$'+text].html(userName);
$win.dialog("close");
});
},
"닫기":function(){
$win.dialog("close");
}
}
});
//console.log($win.parent());
$win.parent().css('font-size','10pt');
}
$('#ext_win').dialog("close").dialog( "option", "position", { my: "center top", at: "center bottom", of: userInfo.$user} );
var $innerContent = $('#inner_table .content');
$innerContent.html('');
$("#user_name").html(userInfo.name+'['+userInfo.city+']');
$('#city_select').html('');
$.each(cityList,function(idx,cityInfo){
var 지역 = cityInfo.지역;
var p태수 = cityInfo.p태수 && currUser.p태수;
var p군사 = cityInfo.p군사 && currUser.p군사;
var p종사 = cityInfo.p종사 && currUser.p종사;
var newInfo = {
지역 : 지역,
규모 : cityInfo.규모,
이름 : cityInfo.이름,
val : cityInfo.val,
city : cityInfo,
p태수 : p태수,
p군사 : p군사,
p종사 : p종사
};
//console.log(newInfo);
if(p태수 || p군사 || p종사){
if(typeof subCityGroupList[지역] == 'undefined'){
subCityGroupList[지역] = [];
}
subCityGroupList[지역].push(newInfo);
subCityList[cityInfo.val] = newInfo;
}
});
$.each(cityGroupOrder,function(idx,groupName){
if(typeof subCityGroupList[groupName] == 'undefined'){
return true;
}
var subList = subCityGroupList[groupName];
var $group = $('<tr><td colspan="4" style="color:skyblue;">【 '+groupName+' 】</td></tr>');
$innerContent.append($group);
subList.sort(function(a,b){
var cmp규모 = city규모[a.규모] - city규모[b.규모];
if(cmp규모 != 0) return cmp규모;
return a.이름.localeCompare(b.이름);
});
var $optgroup = $('<optgroup label=" 【 '+groupName+' 】 " style="color:skyblue;"></optgroup>');
$.each(subList,function(idx,newInfo){
$optgroup.append('<option value="'+newInfo.val+'" style="color:white;">'+newInfo.이름+'</option>');
var cityInfo = newInfo.city;
var $city = $('<tr><td>'+newInfo.이름+'</td></tr>');
var $태수 = cityInfo.$태수.clone();
$city.append($태수);
if(!newInfo.p태수){
$태수.css('color','red');
}
else{
$태수.click(function(){
$('#duty_radio :radio:eq(0)').attr('checked','checked');
$('#duty_radio :radio').button('refresh');
}).css('cursor','pointer');
}
var $군사 = cityInfo.$군사.clone();
$city.append($군사);
if(!newInfo.p군사)$군사.css('color','red');
else{
$군사.click(function(){
$('#duty_radio :radio:eq(1)').attr('checked','checked');
$('#duty_radio :radio').button('refresh');
}).css('cursor','pointer');
}
var $종사 = cityInfo.$종사.clone();
$city.append($종사);
if(!newInfo.p종사)$종사.css('color','red');
else{
$종사.click(function(){
$('#duty_radio :radio:eq(2)').attr('checked','checked');
$('#duty_radio :radio').button('refresh');
}).css('cursor','pointer');
}
$innerContent.append($city);
$city.click(function(){
$('#city_select').val(newInfo.val).change();
});
});
$('#city_select').append($optgroup);
});
tmpOldVal = $('#city_select').val();
$('#city_select').change();
$('#ext_win').dialog("open");
};
var loadDuty = function(){
try{
$('.for_duty').remove();
$.get(basicPath+'b_myBossInfo.php',function(rawData){
$html = $(rawData);
//window.$html = $html;
var cnt =0;
var $tmpTable = $html.filter('#officer_list').eq(0);
$selects = $tmpTable.find("select");
if($selects.length == 0){
alert("수뇌가 아닙니다!");
return false;
}
var setUserAvailable = function($userList,typeName){
$userList.each(function(idx){
var $this = $(this);
var val = $this.val();
var name = $.trim($this.text());
for(var i=name.length-1;i>0;i--){
if(name[i]=='【'){
name = $.trim(name.substr(0,i));
break;
}
}
if(val == '0'){
return true;
}
if(typeof userList[name] != 'undefined'){
userList[name].val = val;
userList[name][typeName] = true;
}
});
};
var setCityAvailiable = function($cityList,typeName){
$cityList.each(function(idx){
var $this = $(this);
var val = $.trim($this.val());
var name = $.trim($this.text());
cityList[name].val = val;
cityList[name][typeName] = true;
});
}
$.each(cityList,function(idx,cityInfo){
cityInfo.p태수=false;
cityInfo.p군사=false;
cityInfo.p종사=false;
});
$.each(userList,function(idx,userInfo){
userInfo.p태수=false;
userInfo.p군사=false;
userInfo.p종사=false;
});
setUserAvailable($selects.eq(1).find("option"),"p태수");
setUserAvailable($selects.eq(3).find("option"),"p군사");
setUserAvailable($selects.eq(5).find("option"),"p종사");
setCityAvailiable($selects.eq(0).find("option"),"p태수");
setCityAvailiable($selects.eq(2).find("option"),"p군사");
setCityAvailiable($selects.eq(4).find("option"),"p종사");
$.each(cityList,function(idx,cityInfo){
//console.log(cityInfo.users.children());
cityInfo.users.children().each(function(idx){
//console.log(this);
var $this = $(this);
var username = $this.data('username');
var userInfo = userList[username];
if(!userInfo){
return true;
}
if(userInfo.val == '-1'){
return true;
}
$name = $this.find('.nameplate');
$name.append('<br class="for_duty">');
var addBtn=function($name,cityInfo,userInfo,type,text,warn){
var enabled = cityInfo['p'+text]&&userInfo['p'+text];
var cityVal = cityInfo.val;
var $btn = $('<button type="button">'+text.substr(0,1)+'</button>');
$btn.addClass('mode_'+type);
$btn.addClass('for_duty');
if(!enabled){
$btn.prop('disabled',true);
$btn.css('background','transparent');
$btn.css('border','0');
}
else{
if(userInfo.is수뇌){
$btn.css('color','red');
}
}
$btn.css('padding','1px 4px');
$btn.css('margin','0');
$btn.click(function(){
if(userInfo.is수뇌){
if(!confirm('수뇌입니다. 임명할까요?')){
return false;
}
}
$.post(basicPath+'j_myBossInfo.php',{
destCityID:cityVal,
destGeneralID:userInfo.val,
officerLevel:type,
action:'임명'
},function(rawData){
cityInfo['p'+text]=false;
var $target = cityInfo.users.find('.mode_'+type);
$target.prop('disabled',true);
$target.css('background','transparent');
$target.css('border','0');
$target.css('color','');
cityInfo['$'+text].html(userInfo.name);
});
});
//console.log($btn);
$name.append($btn);
};
addBtn($name,cityInfo,userInfo,4,'태수');
addBtn($name,cityInfo,userInfo,3,'군사');
addBtn($name,cityInfo,userInfo,2,'종사');
//특수 버튼!
if(userInfo.p태수||userInfo.p군사||userInfo.p종사){
var $btn = $('<button type="button">...</button>');
$btn.addClass('for_duty');
if(userInfo.is수뇌){
$btn.css('color','red');
}
$btn.css('padding','1px 4px');
$btn.css('margin','0');
$btn.click(function(){
if(userInfo.is수뇌){
if(!confirm('수뇌입니다. 임명할까요?')){
return false;
}
}
extDutyWindow(userInfo);
});
$btn.css('border','solid 1px Chocolate').css('background-color','#400000').css('margin-left','4px');
$btn.css('line-hight','20px').css('color','GhostWhite').css('padding','2px 2px').css('height','18px').css('line-height','8px');
//$name.append($btn);
}
});
});
});
}
catch(a){
console.log(a);
}
return false;
};
var loadUser = function(){
$.each(cityList,function(idx,val){
if(typeof val.users == "undefined"){
val.obj.append('<tr><td colspan="12"><table align="center" class="tb_layout cityUser bg0">'+
'<thead><tr>'+
'<td width="100" align="center" class="bg1">이 름</td><td width="100" align="center" class="bg1">통무지</td><td width="100" align="center" class="bg1">부 대</td><td width="60" align="center" class="bg1">자 금</td>'+
'<td width="60" align="center" class="bg1">군 량</td><td width="30" align="center" class="bg1">守</td><td width="60" align="center" class="bg1">병 종</td>'+
'<td width="60" align="center" class="bg1">병 사</td><td width="50" align="center" class="bg1">훈련</td><td width="50" align="center" class="bg1">사기</td><td width="150" align="center" class="bg1">명 령</td>'+
'<td width="60" align="center" class="bg1">삭턴</td><td width="60" align="center" class="bg1">턴</td>'+
'</tr></thead>'+
'<tbody class="cityUserBody"></tbody></table></td></tr>');
val.users = val.obj.find(".cityUserBody");
}
else{
val.users.html("");
}
});
$.get(basicPath+'b_genList.php',function(rawData){
var cnt =0;
var $helper = $('#helper_genlist');
$helper.html('').append($.parseHTML(rawData));
var tmpUsers = $('#general_list tbody tr');
tmpUsers.each(function(idx){
var $this = $(this);
var $city = $this.children('.i_city');
$city.remove();
var cityName = $.trim($city.text());
var $name = $this.children('.i_name');
$name.addClass('nameplate');
var name = $name.find('.t_name').text();
var $work = $this.children('.i_action');
var cityInfo = cityList[cityName];
if(typeof cityInfo == 'undefined'){
return true;
}
if(cityInfo.warn주민)$work.html($work.html().split('정착 장려').join('<span style="color:yellow;">정착 장려</span>'));
if(cityInfo.warn농업)$work.html($work.html().split('농지 개간').join('<span style="color:yellow;">농지 개간</span>'));
if(cityInfo.warn상업)$work.html($work.html().split('상업 투자').join('<span style="color:yellow;">상업 투자</span>'));
if(cityInfo.warn치안)$work.html($work.html().split('치안 강화').join('<span style="color:yellow;">치안 강화</span>'));
if(cityInfo.warn수비)$work.html($work.html().split('수비 강화').join('<span style="color:yellow;">수비 강화</span>'));
if(cityInfo.warn성벽)$work.html($work.html().split('성벽 보수').join('<span style="color:yellow;">성벽 보수</span>'));
var $stat = $this.children('.i_stat');
var stat = $stat.text();
var is수뇌 = stat.indexOf('+')>=0;
$this.data('username',name);
if(cityList[cityName].$태수.text() == name){
cityList[cityName].$태수.html('<span style="color:lightgreen">{0}</span>'.format(name));
}
if(cityList[cityName].$군사.text() == name){
cityList[cityName].$군사.html('<span style="color:lightgreen">{0}</span>'.format(name));
}
if(cityList[cityName].$종사.text() == name){
cityList[cityName].$종사.html('<span style="color:lightgreen">{0}</span>'.format(name));
}
userList[name]={
$city:cityInfo,
city:cityName,
$user:$this,
name:name,
val:'-1',
p태수:false,
p군사:false,
p종사:false,
is수뇌:is수뇌
};
if(cityList[cityName]){
cityList[cityName].users.append($this);
}
});
});
if($("#loadDutyBtn").length == 0){
var $onBossList = $('<button id="loadDutyBtn">인사부 연동</button>');
$onBossList.click(function(){
loadDuty();
return false;
});
$('form').append($onBossList);
}
$('#by_users').show();
};
var mainFunc = function(){
//대상 추출
window.cityList = {};
window.userList = {};
$("form").each(function(){
var $this = $(this);
$this.attr('name','p'+$this.attr('name'));
});
$("table").each(function(idx,val){
$this = $(this);
if($this.attr('class')=='tb_layout bg2'){
$this.addClass('cityInfo');
}
else{
return true;
}
window.$tmpTable = $this;
var cityInfo = {};
//이름 추출
{
var titleText = $this.find('tr:eq(0)>td:eq(0)').text();
var loc0 = titleText.indexOf("【");
var loc1 = titleText.indexOf("|");
var loc2 = titleText.indexOf("】");
var cityLoc = $.trim(titleText.substring(loc0+1,loc1));
var citySize = $.trim(titleText.substring(loc1+1,loc2));
var cityName = $.trim(titleText.substring(loc2+1));
cityName = cityName.replace("[","");
cityName = cityName.replace("]","");
$this.data('cityname',cityName);
cityInfo.지역 = cityLoc;
cityInfo.규모 = citySize;
cityInfo.이름 = cityName;
cityInfo.val = '-1';
cityInfo.p태수 = false;
cityInfo.p군사 = false;
cityInfo.p종사 = false;
}
//주민, 농상치성수
{
var $baseTr = $this.find('tr:eq(1)');
cityInfo.$주민 = $baseTr.find('td:eq(1)');
cityInfo.$농업 = $baseTr.find('td:eq(3)');
cityInfo.$상업 = $baseTr.find('td:eq(5)');
cityInfo.$치안 = $baseTr.find('td:eq(7)');
cityInfo.$수비 = $baseTr.find('td:eq(9)');
cityInfo.$성벽 = $baseTr.find('td:eq(11)');
var tmpVal;
tmpVal = cityInfo.$주민.text().split('/');
cityInfo.주민 = parseInt(tmpVal[0]);
cityInfo.max주민 = parseInt(tmpVal[1]);
tmpVal = cityInfo.$농업.text().split('/');
cityInfo.농업 = parseInt(tmpVal[0]);
cityInfo.max농업 = parseInt(tmpVal[1]);
tmpVal = cityInfo.$상업.text().split('/');
cityInfo.상업 = parseInt(tmpVal[0]);
cityInfo.max상업 = parseInt(tmpVal[1]);
tmpVal = cityInfo.$치안.text().split('/');
cityInfo.치안 = parseInt(tmpVal[0]);
cityInfo.max치안 = parseInt(tmpVal[1]);
tmpVal = cityInfo.$수비.text().split('/');
cityInfo.수비 = parseInt(tmpVal[0]);
cityInfo.max수비 = parseInt(tmpVal[1]);
tmpVal = cityInfo.$성벽.text().split('/');
cityInfo.성벽 = parseInt(tmpVal[0]);
cityInfo.max성벽 = parseInt(tmpVal[1]);
if (cityInfo.주민>cityInfo.max주민*0.9){ cityInfo.$주민.css('color','lightgreen');}
else if (cityInfo.주민>cityInfo.max주민*0.7){ cityInfo.$주민.css('color','yellow');}
else { cityInfo.$주민.css('color','orangered');}
if (cityInfo.농업>cityInfo.max농업*0.8){ cityInfo.$농업.css('color','lightgreen');}
else if (cityInfo.농업>cityInfo.max농업*0.4){ cityInfo.$농업.css('color','yellow');}
else { cityInfo.$농업.css('color','orangered');}
if (cityInfo.상업>cityInfo.max상업*0.8){ cityInfo.$상업.css('color','lightgreen');}
else if (cityInfo.상업>cityInfo.max상업*0.4){ cityInfo.$상업.css('color','yellow');}
else { cityInfo.$상업.css('color','orangered');}
if (cityInfo.치안>cityInfo.max치안*0.8){ cityInfo.$치안.css('color','lightgreen');}
else if (cityInfo.치안>cityInfo.max치안*0.4){ cityInfo.$치안.css('color','yellow');}
else { cityInfo.$치안.css('color','orangered');}
if (cityInfo.수비>cityInfo.max수비*0.6){ cityInfo.$수비.css('color','lightgreen');}
else if (cityInfo.수비>cityInfo.max수비*0.3){ cityInfo.$수비.css('color','yellow');}
else { cityInfo.$수비.css('color','orangered');}
if (cityInfo.성벽>cityInfo.max성벽*0.6){ cityInfo.$성벽.css('color','lightgreen');}
else if (cityInfo.성벽>cityInfo.max성벽*0.3){ cityInfo.$성벽.css('color','yellow');}
else { cityInfo.$성벽.css('color','orangered');}
cityInfo.remain주민 = cityInfo.주민-cityInfo.max주민;
cityInfo.remain농업 = cityInfo.농업-cityInfo.max농업;
cityInfo.remain상업 = cityInfo.상업-cityInfo.max상업;
cityInfo.remain치안 = cityInfo.치안-cityInfo.max치안;
cityInfo.remain수비 = cityInfo.수비-cityInfo.max수비;
cityInfo.remain성벽 = cityInfo.성벽-cityInfo.max성벽;
cityInfo.warn주민 = false;
cityInfo.warn농업 = false;
cityInfo.warn상업 = false;
cityInfo.warn치안 = false;
cityInfo.warn수비 = false;
cityInfo.warn성벽 = false;
if(cityInfo.remain주민 > -10*2000) cityInfo.warn주민 = true;
if(cityInfo.주민 > 0.92*cityInfo.max주민) cityInfo.warn주민 = true;
if(cityInfo.remain농업 > -10*100) cityInfo.warn농업 = true;
if(cityInfo.remain상업 > -10*100) cityInfo.warn상업 = true;
if(cityInfo.remain치안 > -10*100) cityInfo.warn치안 = true;
if(cityInfo.remain수비 > -10*70) cityInfo.warn수비 = true;
if(cityInfo.remain성벽 > -10*70) cityInfo.warn성벽 = true;
if(cityInfo.warn농업) cityInfo.$농업.append('<span class="remain" style="color:yellow;">['+cityInfo.remain농업+']</span>');
if(cityInfo.warn상업) cityInfo.$상업.append('<span class="remain" style="color:yellow;">['+cityInfo.remain상업+']</span>');
if(cityInfo.warn치안) cityInfo.$치안.append('<span class="remain" style="color:yellow;">['+cityInfo.remain치안+']</span>');
if(cityInfo.warn수비) cityInfo.$수비.append('<span class="remain" style="color:yellow;">['+cityInfo.remain수비+']</span>');
if(cityInfo.warn성벽) cityInfo.$성벽.append('<span class="remain" style="color:yellow;">['+cityInfo.remain성벽+']</span>');
}
//태수,군사,종사
{
var $baseTr = $this.find('tr:eq(2)');
cityInfo.$태수 = $baseTr.find('td:eq(7)');
cityInfo.$군사 = $baseTr.find('td:eq(9)');
cityInfo.$종사 = $baseTr.find('td:eq(11)');
}
//기타
{
cityInfo.userCnt = $this.find('tr:eq(3) td:eq(1)').text().split(',').length -1;
}
cityInfo.obj = $this;
cityList[cityInfo.이름] = cityInfo;
});
var $onGenList = $('<button type="button">암행부 연동</button>');
$onGenList.click(function(){
loadUser();
return false;
});
$('form').append($onGenList);
$('table:eq(0) tr:last').after('<tr><td id="sort_more"></td></tr>');
$sort_more = $('#sort_more');
$sort_more.html('재 정렬 순서 :');
var sortIt = function(callback){
var arCity = [];
$('.cityInfo').each(function(){
var $this = $(this);
var cityName = $this.data('cityname');
var cityInfo = cityList[cityName];
arCity.push(cityInfo);
});
arCity = mergeSort(arCity,callback);
//console.log(arCity);
var $anchor = $('.anchor');
//console.log($anchor);
$('body > br').remove();
$('.cityInfo').detach();
$.each(arCity,function(idx,val){
$anchor.before('<br>');
$anchor.before(val.obj);
});
$anchor.before('<br>');
};
var $btn;
$btn = $('<button type="button">도시명</button>').click(function(){
sortIt(function(a,b){
return a.이름.localeCompare(b.이름);
});
});
$sort_more.append($btn);
$btn = $('<button type="button">인구율</button>').click(function(){
sortIt(function(a,b){
return 1.0*a.주민/a.max주민 - 1.0*b.주민/b.max주민;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">남은 주민</button>').click(function(){
sortIt(function(a,b){
return a.remain주민 - b.remain주민;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">남은 농업</button>').click(function(){
sortIt(function(a,b){
return a.remain농업 - b.remain농업;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">남은 상업</button>').click(function(){
sortIt(function(a,b){
return a.remain상업 - b.remain상업;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">남은 치안</button>').click(function(){
sortIt(function(a,b){
return a.remain치안 - b.remain치안;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">남은 수비</button>').click(function(){
sortIt(function(a,b){
return a.remain수비 - b.remain수비;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">남은 성벽</button>').click(function(){
sortIt(function(a,b){
return a.remain성벽 - b.remain성벽;
});
});
$sort_more.append($btn);
$btn = $('<button type="button">배치 장수 수</button>').click(function(){
sortIt(function(a,b){
return b.userCnt - a.userCnt;
});
});
$sort_more.append($btn);
};
mainFunc();
});
File diff suppressed because one or more lines are too long
+8
View File
@@ -0,0 +1,8 @@
/**
* @license
* Lodash <https://lodash.com/>
* Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
File diff suppressed because one or more lines are too long
+74 -76
View File
@@ -1,4 +1,3 @@
/*
function showCityGeneral(cityIdx){
@@ -21,13 +20,13 @@ function loadScenarioPreview(scenarioIdx){
function loadScenarios(){
function loadScenarios() {
$.ajax({
method:'post',
url:'j_load_scenarios.php',
dataType:'json'
}).then(function(result){
if(!result.result){
method: 'post',
url: 'j_load_scenarios.php',
dataType: 'json'
}).then(function(result) {
if (!result.result) {
var deferred = $.Deferred();
deferred.reject('fail');
return deferred.promise();
@@ -37,18 +36,18 @@ function loadScenarios(){
var list = {};
$.each(result.scenario, function(idx, value){
$.each(result.scenario, function(idx, value) {
var title = value.title || "-";
var pat = /【(.*?)[0-9\-_\.a-zA-Z]*】/;
var category = pat.exec(title);
category = category?category[1]:'-';
category = category ? category[1] : '-';
value.title = title;
value.category = category;
value.idx = idx;
value.year = value.year || 180;
if(!(category in list)){
if (!(category in list)) {
list[category] = {};
}
@@ -56,12 +55,12 @@ function loadScenarios(){
});
var $select = $('#scenario_sel');
$.each(list, function(category, items){
$.each(list, function(category, items) {
var $optgroup = $('<optgroup>').attr('label', category);
$.each(items, function(idx, scenario){
$.each(items, function(idx, scenario) {
var $option = $('<option>')
.data('scenario',scenario)
.data('scenario', scenario)
.val(idx)
.html(scenario.title);
$optgroup.append($option);
@@ -75,7 +74,7 @@ function loadScenarios(){
});
}
function scenarioPreview(){
function scenarioPreview() {
var $select = $(this);
var $option = $select.find('option:selected');
@@ -89,125 +88,124 @@ function scenarioPreview(){
$year.html('{0}년'.format(scenario.year));
$npc.html('{0}명'.format(scenario.npc_cnt));
if(scenario.npcEx_cnt == 0){
if (scenario.npcEx_cnt == 0) {
$npcEx.html('');
}
else{
} else {
$npcEx.html('+{0}명'.format(scenario.npcEx_cnt));
}
$nation.html('');
$.each(scenario.nation, function(idx, nation){
$.each(scenario.nation, function(idx, nation) {
$nation.append('<span style="color:{0}">{1}</span> {2}명. {3}<br>'.format(
nation.color, nation.name, nation.generals, nation.cities.join(', ')
));
});
}
function formSetup(){
$.validator.addMethod("autorun_user", function(value,element){
function formSetup() {
$.validator.addMethod("autorun_user", function(value, element) {
var parent = $(element).parent('.input-group');
var checkCnt = parent.find('input:checked').length;
if(value <= 0){
if(checkCnt > 0){
if (value <= 0) {
if (checkCnt > 0) {
return false;
}
return true;
}
if(checkCnt == 0){
if (checkCnt == 0) {
return false;
}
return true;
}, "유효 시간과 옵션은 동시에 설정해야합니다.");
$('#game_form').validate({
rules:{
turnterm:"required",
sync:"required",
scenario:"required",
fiction:"required",
extend:"required",
npcmode:"required",
show_img_level:"required",
tournament_trig:"required",
join_mode:'required',
autorun_user_minutes:{required: true, autorun_user: true, min:0}
rules: {
turnterm: "required",
sync: "required",
scenario: "required",
fiction: "required",
extend: "required",
npcmode: "required",
show_img_level: "required",
tournament_trig: "required",
join_mode: 'required',
autorun_user_minutes: { required: true, autorun_user: true, min: 0 }
},
errorElement: "div",
errorPlacement: function ( error, element ) {
errorPlacement: function(error, element) {
// Add the `help-block` class to the error element
error.addClass( "invalid-feedback" );
error.addClass("invalid-feedback");
if ( element.prop( "type" ) === "checkbox" ) {
error.insertAfter( element.parent( "label" ) );
if (element.prop("type") === "checkbox") {
error.insertAfter(element.parent("label"));
} else {
error.insertAfter( element );
error.insertAfter(element);
}
},
highlight: function ( element, errorClass, validClass ) {
$( element ).addClass( "is-invalid" ).removeClass( "is-valid" );
highlight: function(element, errorClass, validClass) {
$(element).addClass("is-invalid").removeClass("is-valid");
},
unhighlight: function (element, errorClass, validClass) {
$( element ).addClass( "is-valid" ).removeClass( "is-invalid" );
unhighlight: function(element, errorClass, validClass) {
$(element).addClass("is-valid").removeClass("is-invalid");
}
});
$('#game_form').submit(function(e){
$('#game_form').submit(function(e) {
e.preventDefault();
if(!$("#game_form").valid()){
if (!$("#game_form").valid()) {
return;
}
var autorun_user_minutes = parseInt($('#autorun_user_minutes').val());
var autorun_user = [];
if(autorun_user_minutes > 0){
$('.autorun_user_chk:checked').each(function(){
if (autorun_user_minutes > 0) {
$('.autorun_user_chk:checked').each(function() {
autorun_user.push($(this).data('key'));
});
}
$.ajax({
cache:false,
type:'post',
url:'j_install.php',
dataType:'json',
data:{
turnterm:$('#turnterm input:radio:checked').val(),
sync:$('#sync input:radio:checked').val(),
scenario:$('#scenario_sel').val(),
fiction:$('#fiction input:radio:checked').val(),
extend:$('#extend input:radio:checked').val(),
npcmode:$('#npcmode input:radio:checked').val(),
show_img_level:$('#show_img_level input:radio:checked').val(),
tournament_trig:$('#tournament_trig input:radio:checked').val(),
reserve_open:$('#reserve_open').val(),
pre_reserve_open:$('#pre_reserve_open').val(),
join_mode:$('#join_mode input:radio:checked').val(),
autorun_user_minutes:autorun_user_minutes,
autorun_user:autorun_user
cache: false,
type: 'post',
url: 'j_install.php',
dataType: 'json',
data: {
turnterm: $('#turnterm input:radio:checked').val(),
sync: $('#sync input:radio:checked').val(),
scenario: $('#scenario_sel').val(),
fiction: $('#fiction input:radio:checked').val(),
extend: $('#extend input:radio:checked').val(),
block_general_create: $('#block_general_create input:radio:checked').val(),
npcmode: $('#npcmode input:radio:checked').val(),
show_img_level: $('#show_img_level input:radio:checked').val(),
tournament_trig: $('#tournament_trig input:radio:checked').val(),
reserve_open: $('#reserve_open').val(),
pre_reserve_open: $('#pre_reserve_open').val(),
join_mode: $('#join_mode input:radio:checked').val(),
autorun_user_minutes: autorun_user_minutes,
autorun_user: autorun_user
}
}).then(function(result){
}).then(function(result) {
var deferred = $.Deferred();
if(!result.result){
if (!result.result) {
alert(result.reason);
deferred.reject('fail');
}
else{
} else {
alert('게임이 리셋되었습니다.');
deferred.resolve();
}
return deferred.promise();
}).then(function(){
}).then(function() {
location.href = '..';
});
});
}
$(function(){
$(function() {
loadScenarios();
$('#scenario_sel').change(scenarioPreview);
formSetup();
})
})
+685 -653
View File
@@ -1,654 +1,686 @@
function is_touch_device() {
var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
var mq = function(query) {
return window.matchMedia(query).matches;
}
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch) {
return true;
}
// include the 'heartz' as a way to have a non matching MQ to help terminate the join
// https://git.io/vznFH
var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
return mq(query);
}
function reloadWorldMap(option){
var $world_map = $('.world_map');
if($world_map.length == 0){
return;
}
var defaultOption = {
isDetailMap:true, //복잡 지도, 단순 지도
clickableAll:false, //어떤 경우든 클릭을 가능하게 함. 해당 동작의 동작 가능성 여부와는 별도.
selectCallback:null, //callback을 지정시 clickable과 관계 없이 해당 함수를 실행.
hrefTemplate:'#', //도시가 클릭가능할 경우 지정할 href값. {0}은 도시 id로 변환됨
useCachedMap:false, //맵 캐시를 사용
//아래부터는 post query에 들어갈 녀석
year:null, //year값, 연감등에 사용
month:null, //month값, 연감등에 사용
aux:null, //기타 넣고 싶은 값을 입력
neutralView:false, //clickable, 소속 국가, 첩보 여부 등을 반환여부를 설정
showMe:true, //반환 값에 본인이 위치한 도시 값을 반환하도록 설정. neutralView와 별개
targetJson:'j_map.php',
//기타 보조 값
startYear:null,
};
option = $.extend(defaultOption, option);
var useCachedMap = option.useCachedMap;
var isDetailMap = option.isDetailMap;
var clickableAll = option.clickableAll;
var selectCallback = option.selectCallback;
var hrefTemplate = option.hrefTemplate;
var cityPosition = getCityPosition();
var storedOldMapKey = 'sam.{0}.map'.format(serverNick);
var storedStartYear = 'sam.{0}.startYear'.format(serverNick);
//OBJ : startYear, year, month, cityList, nationList, spyList, shownByGeneralList, myCity
function checkReturnObject(obj){
if(!obj.result){
var obj = $.Deferred();
obj.reject('fail');
return obj.promise();
}
if(!$.isNumeric(obj.startYear)
||!$.isNumeric(obj.year)
||!$.isNumeric(obj.month)
){
var obj = $.Deferred();
obj.reject('fail');
return obj.promise();
}
if(useCachedMap){
localStorage.setItem(storedOldMapKey, JSON.stringify([serverID, obj]));
localStorage.setItem(storedStartYear, JSON.stringify(obj.startYear));
}
$world_map.removeClass('draw_required');
return obj;
}
function setMapBackground(obj){
var startYear = obj.startYear;
var year = obj.year;
var month = obj.month;
if(isDetailMap){
$world_map.addClass('map_detail').removeClass('map_basic');
}
else{
$world_map.addClass('map_basic').removeClass('map_detail');
}
var $map_title = $('.map_title_text');
if(year < startYear + 1){
$map_title.css('color', 'magenta');
}
else if(year < startYear + 2){
$map_title.css('color', 'orange');
}
else if(year < startYear + 3){
$map_title.css('color', 'yellow');
}
$map_title_tooltip = $('.map_title .tooltiptext');
$map_title_tooltip.empty();
var tooltipTexts = [];
if(year < startYear + 3){
var startYearText = [];
var remainYear = startYear + 3 - year;
var remainMonth = 12 - month + 1;
if(remainMonth > 0){
remainYear -= 1;
}
if(remainYear){
startYearText.push('{0}년'.format(remainYear));
}
if(remainMonth){
startYearText.push('{0}개월'.format(remainMonth));
}
tooltipTexts.push('초반제한 기간 : {0} ({1}년)'.format(startYearText.join(' '), startYear + 3));
}
var currentTechLimit = Math.floor(Math.max(0, year - startYear) / 5) + 1;
var nextTechLimitYear = currentTechLimit * 5 + startYear;
tooltipTexts.push('기술등급 제한 : {0}등급 ({1}년 해제)'.format(currentTechLimit, nextTechLimitYear, currentTechLimit+1));
$map_title_tooltip.html(tooltipTexts.join('<br>'));
$world_map.removeClass('map_string map_summer map_fall map_winter');
if(month <= 3){
$world_map.addClass('map_spring');
}
else if(month <= 6){
$world_map.addClass('map_summer');
}
else if(month <= 9){
$world_map.addClass('map_fall');
}
else{
$world_map.addClass('map_winter');
}
$map_title.html('{0}年 {1}月'.format(year, month));
return obj;
}
function convertCityObjs(obj){
//원본 Obj는 굉장히 간소하게 온다, Object 형태로 변환해서 사용한다.
function toCityObj(arr){
return {
id:arr[0],
level:arr[1],
state:arr[2],
nationId:(arr[3]>0)?arr[3]:null,
region:arr[4],
supply:(arr[5]!=0)
};
}
function toNationObj(arr){
return {
id:arr[0],
name:arr[1],
color:arr[2],
capital:arr[3]
};
}
var cityList = obj.cityList.map(toCityObj);
var nationList = obj.nationList.map(toNationObj);
nationList = convertDictById(nationList); //array of object -> dict
var spyList = obj.spyList;
var shownByGeneralList = convertSet(obj.shownByGeneralList);//Array -> Set
var myCity = obj.myCity;
var myNation = obj.myNation;
function mergePositionInfo(city){
var id = city.id;
if(!(id in cityPosition)){
return city;
}
var xy_val = cityPosition[id];
city.name = xy_val[0];
city.x = xy_val[1];
city.y = xy_val[2];
return city;
}
function mergeNationInfo(city){
//nationId 값으로 isCapital, color, nation을 통합
var nationId = city.nationId;
if(nationId === null || !(nationId in nationList)){
city.nationId = null;
city.nation = null;
city.color = null;
city.isCapital = false;
return city;
}
var nationObj = nationList[nationId];
city.nation = nationObj.name;
city.color = nationObj.color;
city.isCapital = (nationObj.capital == city.id);
return city;
}
function mergeClickable(city){
//clickable = (remainSpy << 3) | (ourCity << 2) | (shownByGeneral << 1) | clickableAll
var id = city.id;
var nationId = city.nationId;
var clickable = 0;
if(id in spyList){
clickable |= spyList[id] << 3;
}
if(myNation !== null && nationId == myNation){
clickable |= 4;
}
if(shownByGeneralList.hasOwnProperty(id)){
clickable |= 2;
}
if(myCity !== null && id == myCity){
clickable |= 2;
}
if(clickableAll){
clickable |= 1;
}
city.clickable = clickable;
return city;
}
cityList = cityList
.map(mergePositionInfo)
.map(mergeNationInfo)
.map(mergeClickable)
.map(formatCityInfo);
return {
'cityList' : cityList,
'myCity' : myCity
};
}
function drawDetailWorldMap(obj){
var $map_body = $('.world_map .map_body');
var cityList = obj.cityList;
var myCity = obj.myCity;
cityList.forEach(function(city){
var id = city.id;
$('.city_base_{0}'.format(id)).detach();
//이전 도시는 지운다.
var $cityObj = $('<div class="city_base city_base_{0}"></div>'.format(id));
$cityObj.addClass('city_level_{0}'.format(city.level));
$cityObj.data('obj', city).css({'left':city.x-20,'top':city.y-15});
if('color' in city && city.color !== null){
var $bgObj = $('<div class="city_bg"></div>');
$cityObj.append($bgObj);
$bgObj.css({'background-image':'url({0}/b{1}.png)'.format(pathConfig.gameImage, convColorValue(city.color))});
}
var $linkObj = $('<a class="city_link"></a>');
$linkObj.data({'text':city.text,'nation':city.nation,'id':city.id});
$cityObj.append($linkObj);
var $imgObj = $('<div class="city_img"><img src="{0}/cast_{1}.gif"><div class="city_filler"></div></div>'.format(pathConfig.gameImage, city.level));
$linkObj.append($imgObj);
if(city.state > 0){
var $stateObj = $('<div class="city_state"><img src="{0}/event{1}.gif"></div>'.format(pathConfig.gameImage, city.state));
$linkObj.append($stateObj);
}
if(city.nationId && city.nationId > 0){
var flagType = city.supply?'f':'d';
var $flagObj = $('<div class="city_flag"><img src="{0}/{1}{2}.gif"></div>'.format(pathConfig.gameImage, flagType, convColorValue(city.color)));
if(city.isCapital){
var $capitalObj = $('<div class="city_capital"><img src="{0}/event51.gif"></div>'.format(pathConfig.gameImage));
$flagObj.append($capitalObj);
}
$imgObj.append($flagObj);
}
var $nameObj = $('<span class="city_detail_name">{0}</span>'.format(city.name));
$imgObj.append($nameObj);
$map_body.append($cityObj);
});
$world_map.find('.city_base_{0} .city_filler'.format(myCity)).addClass('my_city');
return obj;
}
function drawBasicWorldMap(obj){
var $map_body = $('.world_map .map_body');
var cityList = obj.cityList;
var myCity = obj.myCity;
cityList.forEach(function(city){
var id = city.id;
$('.city_base_{0}'.format(id)).detach();
//이전 도시는 지운다.
var $cityObj = $('<div class="city_base city_base_{0}"></div>'.format(id));
$cityObj.addClass('city_level_{0}'.format(city.level));
$cityObj.data('obj', city).css({'left':city.x-20,'top':city.y-15});
var $linkObj = $('<a class="city_link"></a>');
$linkObj.data({'text':city.text,'nation':city.nation,'id':city.id});
$cityObj.append($linkObj);
var $imgObj = $('<div class="city_img"><div class="city_filler"></div></div>');
if('color' in city && city.color !== null){
$imgObj.css({'background-color':city.color});
}
$linkObj.append($imgObj);
if(city.state > 0){
var state_text = 'wrong';
if(city.state < 10){
state_text = 'good';
}
else if(city.state < 40){
state_text = 'bad';
}
else if(city.state < 50){
state_text = 'war';
}
var $stateObj = $('<div class="city_state city_state_{0}"></div>'.format(state_text));
$imgObj.append($stateObj);
}
//단순 표기에서는 깃발 여부가 없음
if(city.isCapital){
var $capitalObj = $('<div class="city_capital"></div>');
$imgObj.append($capitalObj);
}
var $nameObj = $('<span class="city_detail_name">{0}</span>'.format(city.name));
$imgObj.append($nameObj);
$map_body.append($cityObj);
});
$world_map.find('.city_base_{0} .city_filler'.format(myCity)).addClass('my_city');
return obj;
}
function setMouseWork(obj){
var $tooltip = $('.world_map .city_tooltip');
var $tooltip_city = $tooltip.find('.city_name');
var $tooltip_nation = $tooltip.find('.nation_name');
var $objs = $('.world_map .city_link');
var $map_body = $('.world_map .map_body');
//터치스크린 탭
if(!option.neutralView && is_touch_device()){
$objs.on('touchstart', function(e){
if(window.sam_toggleSingleTap){
return true;
}
var $this = $(this);
var touchMode = $this.data('touchMode');
if($tooltip_city.data('target') != $this.data('id')){
$this.data('touchMode', 1);
}
else if(touchMode === undefined){
$this.data('touchMode', 1);
}
else{
$this.data('touchMode', touchMode + 1);
}
$map_body.data('touchMode', 1);
$tooltip_city.data('target', $this.data('id'));
});
$objs.on('touchend', function(e){
if(window.sam_toggleSingleTap){
return true;
}
var $this = $(this);
var position = $this.parent().position();
$tooltip_city.html($this.data('text'));
var nation_text = $this.data('nation');
if(nation_text){
$tooltip_nation.html(nation_text).show();
}
else{
$tooltip_nation.html('').hide();
}
$tooltip.css({'top': position.top + 25, 'left': position.left + 35}).show();
var touchMode = $this.data('touchMode');
if(touchMode <= 1){
return false;
}
//xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다.
$this.data('touchMode', 0);
});
$map_body.on('touchend',function(e){
if(window.sam_toggleSingleTap){
return true;
}
//위의 touchend bind에 해당하지 않는 경우 -> 빈 지도 터치
$tooltip.hide();
});
}
//Mouse over 모드 작동
$map_body.on('mousemove', function(e){
if($(this).data('touchMode')){
return true;
}
var parentOffset = $map_body.offset();
var relX = e.pageX - parentOffset.left;
var relY = e.pageY - parentOffset.top;
$tooltip.css({'top': relY + 10, 'left': relX + 10});
});
$objs.on('mouseenter', function(e){
if($map_body.data('touchMode')){
return true;
}
var $this = $(this);
$tooltip_city.data('target', $this.data('id'));
$tooltip_city.html($this.data('text'));
var nation_text = $this.data('nation');
if(nation_text){
$tooltip_nation.html(nation_text).show();
}
else{
$tooltip_nation.html('').hide();
}
$tooltip.show();
});
$objs.on('mouseleave', function(event){
$tooltip.hide();
});
$objs.on('click', function(e){
//xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다.
var touchMode = $(this).data('touchMode');
if(touchMode === undefined){
return;
}
if(touchMode === 1){
return false;
}
});
return obj;
}
function setCityClickable(obj){
obj.cityList.forEach(function(city){
var $cityLink = $world_map.find('.city_base_{0} .city_link'.format(city.id));
if('clickable' in city && city.clickable > 0){
$cityLink.attr('href',hrefTemplate.format(city.id));
}
if(selectCallback){
$cityLink.click(function(){
return selectCallback(city);
});
}
});
return obj;
}
function saveCityInfo(obj){
$world_map.data('cityInfo', obj);
return obj;
}
var $hideCityNameBtn = $world_map.find('.map_toggle_cityname');
if(localStorage.getItem('sam.hideMapCityName') == 'yes'){
$world_map.addClass('hide_cityname');
$hideCityNameBtn.addClass('active').attr('aria-pressed', 'true');
}
$hideCityNameBtn.click(function(){
//이전 상태 확인
var state = !$hideCityNameBtn.hasClass('active');
if(state){
$world_map.addClass('hide_cityname');
localStorage.setItem('sam.hideMapCityName', 'yes');
}
else{
$world_map.removeClass('hide_cityname');
localStorage.setItem('sam.hideMapCityName', 'no');
}
});
var $toggleSingleTapBtn = $world_map.find('.map_toggle_single_tap');
if(localStorage.getItem('sam.toggleSingleTap') == 'yes'){
window.sam_toggleSingleTap = true;
$toggleSingleTapBtn.addClass('active').attr('aria-pressed', 'true');
}
else{
window.sam_toggleSingleTap = false;
}
var $map_body = $('.world_map .map_body');
$toggleSingleTapBtn.click(function(){
//이전 상태 확인
var state = !$toggleSingleTapBtn.hasClass('active');
if(state){
$map_body.removeData('touchMode');
localStorage.setItem('sam.toggleSingleTap', 'yes');
window.sam_toggleSingleTap = true;
}
else{
localStorage.setItem('sam.toggleSingleTap', 'no');
window.sam_toggleSingleTap = false;
}
});
if(isDetailMap){
$world_map.addClass('map_detail');
}
else{
$world_map.removeClass('map_datail');
}
//deferred mode of jQuery. != promise-then.
var deferred = $.ajax({
url: option.targetJson,
type: 'post',
dataType:'json',
data: {
data: JSON.stringify({
neutralView:option.neutralView,
year:option.year,
month:option.month,
showMe:option.showMe,
aux:option.aux
})
}
});
deferred
.then(checkReturnObject)
.then(setMapBackground)
.then(convertCityObjs)
.then(isDetailMap?drawDetailWorldMap:drawBasicWorldMap)
.then(setMouseWork)
.then(setCityClickable)
.then(saveCityInfo);
if($world_map.hasClass('draw_required')){
if(useCachedMap){
//일단 불러옴
do{
var storedMap = localStorage.getItem(storedOldMapKey);
if(!storedMap){
break;
}
storedMap = JSON.parse(storedMap);
var storedServerID = storedMap[0];
if(storedServerID != serverID){
break;
}
storedMap = storedMap[1];
storedMap = setMapBackground(storedMap);
storedMap = convertCityObjs(storedMap);
if(isDetailMap){
storedMap = drawDetailWorldMap(storedMap);
}
else{
storedMap = drawBasicWorldMap(storedMap);
}
storedMap = setMouseWork(storedMap);
storedMap = setCityClickable(storedMap);
storedMap = saveCityInfo(storedMap);
}while(false);
}
else if(option.year && option.month){
var startYear = localStorage.getItem(storedStartYear);
if(startYear){
startYear = JSON.parse(startYear);
}
else{
startYear = option.year;
}
var tmp = {
year : option.year,
month : option.month,
startYear : startYear
};
setMapBackground(tmp);
}
}
}
$(function(){
if(is_touch_device()){
$('.map_body .map_toggle_single_tap').show();
}
function is_touch_device() {
var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
var mq = function(query) {
return window.matchMedia(query).matches;
}
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch) {
return true;
}
// include the 'heartz' as a way to have a non matching MQ to help terminate the join
// https://git.io/vznFH
var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
return mq(query);
}
function reloadWorldMap(option, drawTarget) {
if (drawTarget === undefined || drawTarget === null) {
drawTarget = '.world_map'
}
var $world_map = $(drawTarget);
if ($world_map.length == 0) {
return;
}
var defaultOption = {
isDetailMap: true, //복잡 지도, 단순 지도
clickableAll: false, //어떤 경우든 클릭을 가능하게 함. 해당 동작의 동작 가능성 여부와는 별도.
selectCallback: null, //callback을 지정시 clickable과 관계 없이 해당 함수를 실행.
hrefTemplate: '#', //도시가 클릭가능할 경우 지정할 href값. {0}은 도시 id로 변환됨
useCachedMap: false, //맵 캐시를 사용
//아래부터는 post query에 들어갈 녀석
year: null, //year값, 연감등에 사용
month: null, //month값, 연감등에 사용
aux: null, //기타 넣고 싶은 값을 입력
neutralView: false, //clickable, 소속 국가, 첩보 여부 등을 반환여부를 설정
showMe: true, //반환 값에 본인이 위치한 도시 값을 반환하도록 설정. neutralView와 별개
targetJson: 'j_map.php',
reqType: 'post',
dynamicMapTheme: false,
callback: null,
//기타 보조 값
startYear: null,
};
option = $.extend(defaultOption, option);
var useCachedMap = option.useCachedMap;
var isDetailMap = option.isDetailMap;
var clickableAll = option.clickableAll;
var selectCallback = option.selectCallback;
var hrefTemplate = option.hrefTemplate;
var cityPosition = getCityPosition();
var storedOldMapKey = 'sam.{0}.map'.format(serverNick);
var storedStartYear = 'sam.{0}.startYear'.format(serverNick);
//OBJ : startYear, year, month, cityList, nationList, spyList, shownByGeneralList, myCity
function checkReturnObject(obj) {
if (!obj.result) {
var obj = $.Deferred();
obj.reject('fail');
return obj.promise();
}
if (!$.isNumeric(obj.startYear) ||
!$.isNumeric(obj.year) ||
!$.isNumeric(obj.month)
) {
var obj = $.Deferred();
obj.reject('fail');
return obj.promise();
}
if (useCachedMap) {
localStorage.setItem(storedOldMapKey, JSON.stringify([serverID, obj]));
localStorage.setItem(storedStartYear, JSON.stringify(obj.startYear));
}
$world_map.removeClass('draw_required');
return obj;
}
function setMapBackground(obj) {
function setTheme() {
var oldTheme = $world_map.data('currentTheme');
var newTheme = obj.theme;
if (oldTheme === newTheme) {
return;
}
if (oldTheme) {
$world_map.removeClass('map_theme_' + oldTheme);
}
$world_map.addClass('map_theme_' + newTheme);
$world_map.data('currentTheme', newTheme);
}
if (option.dynamicMapTheme) {
setTheme();
}
var startYear = obj.startYear;
var year = obj.year;
var month = obj.month;
if (isDetailMap) {
$world_map.addClass('map_detail').removeClass('map_basic');
} else {
$world_map.addClass('map_basic').removeClass('map_detail');
}
var $map_title = $('.map_title_text');
if (year < startYear + 1) {
$map_title.css('color', 'magenta');
} else if (year < startYear + 2) {
$map_title.css('color', 'orange');
} else if (year < startYear + 3) {
$map_title.css('color', 'yellow');
}
$map_title_tooltip = $('.map_title .tooltiptext');
$map_title_tooltip.empty();
var tooltipTexts = [];
if (year < startYear + 3) {
var startYearText = [];
var remainYear = startYear + 3 - year;
var remainMonth = 12 - month + 1;
if (remainMonth > 0) {
remainYear -= 1;
}
if (remainYear) {
startYearText.push('{0}년'.format(remainYear));
}
if (remainMonth) {
startYearText.push('{0}개월'.format(remainMonth));
}
tooltipTexts.push('초반제한 기간 : {0} ({1}년)'.format(startYearText.join(' '), startYear + 3));
}
var currentTechLimit = Math.floor(Math.max(0, year - startYear) / 5) + 1;
var nextTechLimitYear = currentTechLimit * 5 + startYear;
tooltipTexts.push('기술등급 제한 : {0}등급 ({1}년 해제)'.format(currentTechLimit, nextTechLimitYear, currentTechLimit + 1));
$map_title_tooltip.html(tooltipTexts.join('<br>'));
$world_map.removeClass('map_string map_summer map_fall map_winter');
if (month <= 3) {
$world_map.addClass('map_spring');
} else if (month <= 6) {
$world_map.addClass('map_summer');
} else if (month <= 9) {
$world_map.addClass('map_fall');
} else {
$world_map.addClass('map_winter');
}
$map_title.html('{0}年 {1}月'.format(year, month));
return obj;
}
function convertCityObjs(obj) {
//원본 Obj는 굉장히 간소하게 온다, Object 형태로 변환해서 사용한다.
function toCityObj(arr) {
return {
id: arr[0],
level: arr[1],
state: arr[2],
nationId: (arr[3] > 0) ? arr[3] : null,
region: arr[4],
supply: (arr[5] != 0)
};
}
function toNationObj(arr) {
return {
id: arr[0],
name: arr[1],
color: arr[2],
capital: arr[3]
};
}
var cityList = obj.cityList.map(toCityObj);
var nationList = obj.nationList.map(toNationObj);
nationList = convertDictById(nationList); //array of object -> dict
var spyList = obj.spyList;
var shownByGeneralList = convertSet(obj.shownByGeneralList); //Array -> Set
var myCity = obj.myCity;
var myNation = obj.myNation;
function mergePositionInfo(city) {
var id = city.id;
if (!(id in cityPosition)) {
return city;
}
var xy_val = cityPosition[id];
city.name = xy_val[0];
city.x = xy_val[1];
city.y = xy_val[2];
return city;
}
function mergeNationInfo(city) {
//nationId 값으로 isCapital, color, nation을 통합
var nationId = city.nationId;
if (nationId === null || !(nationId in nationList)) {
city.nationId = null;
city.nation = null;
city.color = null;
city.isCapital = false;
return city;
}
var nationObj = nationList[nationId];
city.nation = nationObj.name;
city.color = nationObj.color;
city.isCapital = (nationObj.capital == city.id);
return city;
}
function mergeClickable(city) {
//clickable = (defaultCity << 4 ) | (remainSpy << 3) | (ourCity << 2) | (shownByGeneral << 1) | clickableAll
var id = city.id;
var nationId = city.nationId;
var clickable = 16;
if (id in spyList) {
clickable |= spyList[id] << 3;
}
if (myNation !== null && nationId == myNation) {
clickable |= 4;
}
if (shownByGeneralList.hasOwnProperty(id)) {
clickable |= 2;
}
if (myCity !== null && id == myCity) {
clickable |= 2;
}
if (clickableAll) {
clickable |= 1;
}
city.clickable = clickable;
return city;
}
cityList = cityList
.map(mergePositionInfo)
.map(mergeNationInfo)
.map(mergeClickable)
.map(formatCityInfo);
return {
'cityList': cityList,
'myCity': myCity
};
}
function drawDetailWorldMap(obj) {
var $map_body = $(drawTarget + ' .map_body');
var cityList = obj.cityList;
var myCity = obj.myCity;
cityList.forEach(function(city) {
var id = city.id;
$('.city_base_{0}'.format(id)).detach();
//이전 도시는 지운다.
var $cityObj = $('<div class="city_base city_base_{0}"></div>'.format(id));
$cityObj.addClass('city_level_{0}'.format(city.level));
$cityObj.data('obj', city).css({ 'left': city.x - 20, 'top': city.y - 15 });
if ('color' in city && city.color !== null) {
var $bgObj = $('<div class="city_bg"></div>');
$cityObj.append($bgObj);
$bgObj.css({ 'background-image': 'url({0}/b{1}.png)'.format(pathConfig.gameImage, convColorValue(city.color)) });
}
var $linkObj = $('<a class="city_link"></a>');
$linkObj.data({ 'text': city.text, 'nation': city.nation, 'id': city.id });
$cityObj.append($linkObj);
var $imgObj = $('<div class="city_img"><img src="{0}/cast_{1}.gif"><div class="city_filler"></div></div>'.format(pathConfig.gameImage, city.level));
$linkObj.append($imgObj);
if (city.state > 0) {
var $stateObj = $('<div class="city_state"><img src="{0}/event{1}.gif"></div>'.format(pathConfig.gameImage, city.state));
$linkObj.append($stateObj);
}
if (city.nationId && city.nationId > 0) {
var flagType = city.supply ? 'f' : 'd';
var $flagObj = $('<div class="city_flag"><img src="{0}/{1}{2}.gif"></div>'.format(pathConfig.gameImage, flagType, convColorValue(city.color)));
if (city.isCapital) {
var $capitalObj = $('<div class="city_capital"><img src="{0}/event51.gif"></div>'.format(pathConfig.gameImage));
$flagObj.append($capitalObj);
}
$imgObj.append($flagObj);
}
var $nameObj = $('<span class="city_detail_name">{0}</span>'.format(city.name));
$imgObj.append($nameObj);
$map_body.append($cityObj);
});
$world_map.find('.city_base_{0} .city_filler'.format(myCity)).addClass('my_city');
return obj;
}
function drawBasicWorldMap(obj) {
var $map_body = $(drawTarget + ' .map_body');
var cityList = obj.cityList;
var myCity = obj.myCity;
cityList.forEach(function(city) {
var id = city.id;
$('.city_base_{0}'.format(id)).detach();
//이전 도시는 지운다.
var $cityObj = $('<div class="city_base city_base_{0}"></div>'.format(id));
$cityObj.addClass('city_level_{0}'.format(city.level));
$cityObj.data('obj', city).css({ 'left': city.x - 20, 'top': city.y - 15 });
var $linkObj = $('<a class="city_link"></a>');
$linkObj.data({ 'text': city.text, 'nation': city.nation, 'id': city.id });
$cityObj.append($linkObj);
var $imgObj = $('<div class="city_img"><div class="city_filler"></div></div>');
if ('color' in city && city.color !== null) {
$imgObj.css({ 'background-color': city.color });
}
$linkObj.append($imgObj);
if (city.state > 0) {
var state_text = 'wrong';
if (city.state < 10) {
state_text = 'good';
} else if (city.state < 40) {
state_text = 'bad';
} else if (city.state < 50) {
state_text = 'war';
}
var $stateObj = $('<div class="city_state city_state_{0}"></div>'.format(state_text));
$imgObj.append($stateObj);
}
//단순 표기에서는 깃발 여부가 없음
if (city.isCapital) {
var $capitalObj = $('<div class="city_capital"></div>');
$imgObj.append($capitalObj);
}
var $nameObj = $('<span class="city_detail_name">{0}</span>'.format(city.name));
$imgObj.append($nameObj);
$map_body.append($cityObj);
});
$world_map.find('.city_base_{0} .city_filler'.format(myCity)).addClass('my_city');
return obj;
}
function setMouseWork(obj) {
var $tooltip = $(drawTarget + ' .city_tooltip');
var $tooltip_city = $tooltip.find('.city_name');
var $tooltip_nation = $tooltip.find('.nation_name');
var $objs = $(drawTarget + ' .city_link');
var $map_body = $(drawTarget + ' .map_body');
//터치스크린 탭
if (!option.neutralView && is_touch_device()) {
$objs.on('touchstart', function(e) {
if (window.sam_toggleSingleTap) {
return true;
}
var $this = $(this);
var touchMode = $this.data('touchMode');
if ($tooltip_city.data('target') != $this.data('id')) {
$this.data('touchMode', 1);
} else if (touchMode === undefined) {
$this.data('touchMode', 1);
} else {
$this.data('touchMode', touchMode + 1);
}
$map_body.data('touchMode', 1);
$tooltip_city.data('target', $this.data('id'));
});
$objs.on('touchend', function(e) {
if (window.sam_toggleSingleTap) {
return true;
}
var $this = $(this);
var position = $this.parent().position();
$tooltip_city.html($this.data('text'));
var nation_text = $this.data('nation');
if (nation_text) {
$tooltip_nation.html(nation_text).show();
} else {
$tooltip_nation.html('').hide();
}
var left = position.left;
var top = position.top;
var scale = $map_body.data('scale');
if (scale) {
left /= scale;
top /= scale;
}
$tooltip.css({ 'top': top + 25, 'left': left + 35 }).show();
var touchMode = $this.data('touchMode');
if (touchMode <= 1) {
return false;
}
//xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다.
$this.data('touchMode', 0);
});
$map_body.on('touchend', function(e) {
if (window.sam_toggleSingleTap) {
return true;
}
//위의 touchend bind에 해당하지 않는 경우 -> 빈 지도 터치
$tooltip.hide();
});
}
//Mouse over 모드 작동
$map_body.on('mousemove', function(e) {
if ($(this).data('touchMode')) {
return true;
}
var rect = this.getBoundingClientRect();
var left = (e.clientX - rect.left - this.clientLeft + this.scrollLeft);
var top = (e.clientY - rect.top - this.clientTop + this.scrollTop);
var scale = $map_body.data('scale');
if (scale) {
left /= scale;
top /= scale;
}
$tooltip.css({ 'top': top + 10, 'left': left + 10 });
});
$objs.on('mouseenter', function(e) {
if ($map_body.data('touchMode')) {
return true;
}
var $this = $(this);
$tooltip_city.data('target', $this.data('id'));
$tooltip_city.html($this.data('text'));
var nation_text = $this.data('nation');
if (nation_text) {
$tooltip_nation.html(nation_text).show();
} else {
$tooltip_nation.html('').hide();
}
$tooltip.show();
});
$objs.on('mouseleave', function(event) {
$tooltip.hide();
});
$objs.on('click', function(e) {
//xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다.
var touchMode = $(this).data('touchMode');
if (touchMode === undefined) {
return;
}
if (touchMode === 1) {
return false;
}
});
return obj;
}
function setCityClickable(obj) {
obj.cityList.forEach(function(city) {
var $cityLink = $world_map.find('.city_base_{0} .city_link'.format(city.id));
if ('clickable' in city && city.clickable > 0) {
$cityLink.attr('href', hrefTemplate.format(city.id));
}
if (selectCallback) {
$cityLink.click(function() {
return selectCallback(city);
});
}
});
return obj;
}
function saveCityInfo(obj) {
$world_map.data('cityInfo', obj);
return obj;
}
var $hideCityNameBtn = $world_map.find('.map_toggle_cityname');
if (localStorage.getItem('sam.hideMapCityName') == 'yes') {
$world_map.addClass('hide_cityname');
$hideCityNameBtn.addClass('active').attr('aria-pressed', 'true');
}
$hideCityNameBtn.click(function() {
//이전 상태 확인
var state = !$hideCityNameBtn.hasClass('active');
if (state) {
$world_map.addClass('hide_cityname');
localStorage.setItem('sam.hideMapCityName', 'yes');
} else {
$world_map.removeClass('hide_cityname');
localStorage.setItem('sam.hideMapCityName', 'no');
}
});
var $toggleSingleTapBtn = $world_map.find('.map_toggle_single_tap');
if (localStorage.getItem('sam.toggleSingleTap') == 'yes') {
window.sam_toggleSingleTap = true;
$toggleSingleTapBtn.addClass('active').attr('aria-pressed', 'true');
} else {
window.sam_toggleSingleTap = false;
}
var $map_body = $(drawTarget + ' .map_body');
$toggleSingleTapBtn.click(function() {
//이전 상태 확인
var state = !$toggleSingleTapBtn.hasClass('active');
if (state) {
$map_body.removeData('touchMode');
localStorage.setItem('sam.toggleSingleTap', 'yes');
window.sam_toggleSingleTap = true;
} else {
localStorage.setItem('sam.toggleSingleTap', 'no');
window.sam_toggleSingleTap = false;
}
});
if (isDetailMap) {
$world_map.addClass('map_detail');
} else {
$world_map.removeClass('map_datail');
}
//deferred mode of jQuery. != promise-then.
var deferred = $.ajax({
url: option.targetJson,
type: option.reqType,
dataType: 'json',
ifModified: true,
data: {
data: JSON.stringify({
neutralView: option.neutralView,
year: option.year,
month: option.month,
showMe: option.showMe,
aux: option.aux
})
}
});
var rawObject = null;
deferred
.then(function(data) {
rawObject = data;
return data;
})
.then(checkReturnObject)
.then(setMapBackground)
.then(convertCityObjs)
.then(isDetailMap ? drawDetailWorldMap : drawBasicWorldMap)
.then(setMouseWork)
.then(setCityClickable)
.then(saveCityInfo)
.then(function(data) {
if (option.callback) {
option.callback(data, rawObject);
}
});
if ($world_map.hasClass('draw_required')) {
if (useCachedMap) {
//일단 불러옴
do {
var storedMap = localStorage.getItem(storedOldMapKey);
if (!storedMap) {
break;
}
storedMap = JSON.parse(storedMap);
var storedServerID = storedMap[0];
if (storedServerID != serverID) {
break;
}
storedMap = storedMap[1];
storedMap = setMapBackground(storedMap);
storedMap = convertCityObjs(storedMap);
if (isDetailMap) {
storedMap = drawDetailWorldMap(storedMap);
} else {
storedMap = drawBasicWorldMap(storedMap);
}
storedMap = setMouseWork(storedMap);
storedMap = setCityClickable(storedMap);
storedMap = saveCityInfo(storedMap);
} while (false);
} else if (option.year && option.month) {
var startYear = localStorage.getItem(storedStartYear);
if (startYear) {
startYear = JSON.parse(startYear);
} else {
startYear = option.year;
}
var tmp = {
year: option.year,
month: option.month,
startYear: startYear
};
setMapBackground(tmp);
}
}
}
$(function() {
if (is_touch_device()) {
$('.map_body .map_toggle_single_tap').show();
}
})
+166 -84
View File
@@ -1,85 +1,167 @@
jQuery(function($){
var initCustomCSSForm = function(){
var lastTimeOut = null;
var $obj = $('#custom_css');
var key = 'sam_customCSS';
var text = localStorage.getItem(key);
if(text){
$obj.val(text);
console.log(text);
}
if($obj.on('change keyup paste', function(){
var newText = $obj.val();
if(text == newText){
return;
}
if(lastTimeOut){
clearTimeout(lastTimeOut);
}
$obj.css('background-color', '#222222');
lastTimeOut = setTimeout(function(){
text = $obj.val();
localStorage.setItem(key, text);
$obj.css('background-color', 'black');
}, 500);
}));
}
$('.load_old_log').click(function(){
var $thisBtn = $(this);
var logType = $thisBtn.data('log_type');
var $last = $('.log_{0}:last'.format(logType));
var reqTo = null;
if($last.length){
reqTo = $last.data('seq');
}
$.post({
url:'j_general_log_old.php',
dataType:'json',
data:{
to:reqTo,
type:logType
}
}).then(function(data){
if(!data){
return quickReject('로그를 받아오지 못했습니다.');
}
if(!data.result){
return quickReject('로그를 받아오지 못했습니다. : '+data.reason);
}
var keys = Object.keys(data.log);
if(keys.length > 1 && keys[0] < keys[1]){
keys.reverse();
}
if(keys == 0){
$thisBtn.hide();
return;
}
var html = [];
$.each(keys, function(_, key){
if($('#log_{0}_{1}'.format(logType, key)).length){
return true;
}
var item = data.log[key];
html.push("<div class='log_{0}' id='log_{0}_{1}' data-seq='{1}'>{2}</div>".format(logType, key, item));
});
$('#{0}Plate'.format(logType)).append(html);
}, errUnknown)
.fail(function(reason){
alert(reason);
location.reload();
});
})
initCustomCSSForm();
jQuery(function($) {
var initCustomCSSForm = function() {
var lastTimeOut = null;
var $obj = $('#custom_css');
var key = 'sam_customCSS';
var text = localStorage.getItem(key);
if (text) {
$obj.val(text);
console.log(text);
}
if ($obj.on('change keyup paste', function() {
var newText = $obj.val();
if (text == newText) {
return;
}
if (lastTimeOut) {
clearTimeout(lastTimeOut);
}
$obj.css('background-color', '#222222');
lastTimeOut = setTimeout(function() {
text = $obj.val();
localStorage.setItem(key, text);
$obj.css('background-color', 'black');
}, 500);
}));
}
$('.load_old_log').click(function() {
var $thisBtn = $(this);
var logType = $thisBtn.data('log_type');
var $last = $('.log_{0}:last'.format(logType));
var reqTo = null;
if ($last.length) {
reqTo = $last.data('seq');
}
$.post({
url: 'j_general_log_old.php',
dataType: 'json',
data: {
to: reqTo,
type: logType
}
}).then(function(data) {
if (!data) {
return quickReject('로그를 받아오지 못했습니다.');
}
if (!data.result) {
return quickReject('로그를 받아오지 못했습니다. : ' + data.reason);
}
var keys = Object.keys(data.log);
if (keys.length > 1 && keys[0] < keys[1]) {
keys.reverse();
}
if (keys == 0) {
$thisBtn.hide();
return;
}
var html = [];
$.each(keys, function(_, key) {
if ($('#log_{0}_{1}'.format(logType, key)).length) {
return true;
}
var item = data.log[key];
html.push("<div class='log_{0}' id='log_{0}_{1}' data-seq='{1}'>{2}</div>".format(logType, key, item));
});
$('#{0}Plate'.format(logType)).append(html);
}, errUnknown)
.fail(function(reason) {
alert(reason);
location.reload();
});
})
initCustomCSSForm();
$('#die_immediately').click(function() {
if (!confirm('정말로 삭제하시겠습니까?')) {
return false;
}
$.post({
url: 'j_die_immediately.php',
dataType: 'json',
}).then(function(data) {
if (!data) {
return quickReject('실패했습니다.');
}
if (!data.result) {
return quickReject(data.reason);
}
location.replace('..');
}, errUnknown)
.fail(function(reason) {
alert(reason);
location.reload();
});
return false;
return false;
});
$('#vacation').click(function() {
if (!confirm('휴가 기능을 신청할까요?')) {
return false;
}
$.post({
url: 'j_vacation.php',
dataType: 'json',
}).then(function(data) {
if (!data) {
return quickReject('실패했습니다.');
}
if (!data.result) {
return quickReject(data.reason);
}
location.reload();
}, errUnknown)
.fail(function(reason) {
alert(reason);
location.reload();
});
return false;
return false;
});
$('#set_my_setting').click(function() {
$.post({
url: 'j_set_my_setting.php',
dataType: 'json',
data: {
tnmt: $('.tnmt:checked').val(),
defence_train: $('#defence_train').val(),
use_treatment: $('#use_treatment').val(),
use_auto_nation_turn: $('#use_auto_nation_turn').val(),
}
}).then(function(data) {
if (!data) {
return quickReject('실패했습니다.');
}
if (!data.result) {
return quickReject(data.reason);
}
location.reload();
}, errUnknown)
.fail(function(reason) {
alert(reason);
location.reload();
});
return false;
return false;
});
});
+40 -3
View File
@@ -33,6 +33,35 @@ jQuery(function ($) {
var $disabled = $(itemFrameDisabled.format('&lt;비활성화 항목들&gt;')).addClass('filtered');
$disabledList.append($disabled);
var lastInfoObj = null;
var lastInfoData = null;
var onChoose = function(evt){
//$(evt.item).find('.help-message').popopver('disable');
if(lastInfoObj){
lastInfoObj.popover('hide');
}
}
var onUnchoose = function(evt){
var $item = $(evt.item);//.find('.help-message').popopver('enable');
var $helpMessage = $item.find('.help-message');
if(!$helpMessage.length){
return;
}
if(lastInfoData != $item.data('value')){
$helpMessage.popover('show')
lastInfoData = $item.data('value');
lastInfoObj = $helpMessage;
}
else{
$helpMessage.popover('hide');
lastInfoData = null;
lastInfoObj = null;
}
}
$.each(availablePriority, function (key, val) {
if (val in usedKey) {
return true;
@@ -45,12 +74,16 @@ jQuery(function ($) {
$disabledList.sortable({
group: priorityKey,
filter: '.filtered',
onChoose,onChoose,
onUnchoose:onUnchoose,
animation: 150
});
$enabledList.sortable({
group: priorityKey,
filter: '.filtered',
onChoose,onChoose,
onUnchoose:onUnchoose,
animation: 150
});
@@ -59,14 +92,18 @@ jQuery(function ($) {
if(!(itemValue in btnHelpMessage)){
return true;
}
var helpText = btnHelpMessage[itemValue];
$item.find('.help-message').popover({
var $helpMessage = $item.find('.help-message');
$helpMessage.popover({
content:helpText,
placement:'right',
placement:'top',
html:true,
trigger:'hover'
});
$item.mouseleave(function(){
$helpMessage.popover('hide');
});
});
}
+244 -101
View File
@@ -1,102 +1,245 @@
function reserveTurn(turnList, command, arg){
var target;
if(isChiefTurn){
target = 'j_set_chief_command.php';
}
else{
target = 'j_set_general_command.php';
}
$.post({
url:target,
dataType:'json',
data:{
action:command,
turnList:turnList,
arg:JSON.stringify(arg)
}
}).then(function(data){
if(!data.result){
alert(data.reason);
return;
}
if(!isChiefTurn){
window.location.href = './';
}
else{
window.location.href = 'b_chiefcenter.php';
}
}, errUnknown);
}
jQuery(function($){
window.submitAction = function(){
//checkCommandArg 참고
var availableArgumentList = {
'string':[
'nationName', 'optionText', 'itemType', 'nationType', 'itemCode',
],
'int':[
'crewType', 'destGeneralID', 'destCityID', 'destNationID',
'amount', 'colorType',
'year', 'month',
'srcArmType', 'destArmType', //숙련전환 전용
],
'boolean':[
'isGold', 'buyRice',
],
'integerArray':[
'destNationIDList', 'destGeneralIDList', 'amountList'
]
}
var handlerList = {
'string':function($obj){
return $.trim($obj.eq(0).val());
},
'int':function($obj){
return parseInt($obj.eq(0).val());
},
'boolean':function($obj){
switch ($obj.eq(0).val().toLowerCase()) {
case "true": case "yes": case "1":
return true;
case "false": case "no": case "0":
return false;
default:
throw new Error ("Boolean.parse: Cannot convert string to boolean.");
}
},
'integerArray':function($obj){
return $obj.map(function(){
return parseInt($(this).val());
});
}
}
var argument = {};
for (var typeName in availableArgumentList) {
availableArgumentList[typeName].forEach(function(argName){
var $obj = $('#'+argName);
if($obj.length == 0){
$obj = $('.'+argName);
if($obj.length == 0){
return;
}
}
argument[argName] = handlerList[typeName]($obj);
});
}
console.log(argument);
reserveTurn(turnList, command, argument);
};
$('#commonSubmit').click(submitAction);
function reserveTurn(turnList, command, arg) {
var target;
if (isChiefTurn) {
target = 'j_set_chief_command.php';
} else {
target = 'j_set_general_command.php';
}
$.post({
url: target,
dataType: 'json',
data: {
action: command,
turnList: turnList,
arg: JSON.stringify(arg)
}
}).then(function(data) {
if (!data.result) {
alert(data.reason);
return;
}
if (!isChiefTurn) {
window.location.href = './';
} else {
window.location.href = 'b_chiefcenter.php';
}
}, errUnknown);
}
jQuery(function($) {
window.submitAction = function() {
//checkCommandArg 참고
var availableArgumentList = {
'string': [
'nationName', 'optionText', 'itemType', 'nationType', 'itemCode', 'commandType',
],
'int': [
'crewType', 'destGeneralID', 'destCityID', 'destNationID',
'amount', 'colorType',
'year', 'month',
'srcArmType', 'destArmType', //숙련전환 전용
],
'boolean': [
'isGold', 'buyRice',
],
'integerArray': [
'destNationIDList', 'destGeneralIDList', 'amountList'
]
}
var handlerList = {
'string': function($obj) {
return $.trim($obj.eq(0).val());
},
'int': function($obj) {
return parseInt($obj.eq(0).val());
},
'boolean': function($obj) {
switch ($obj.eq(0).val().toLowerCase()) {
case "true":
case "yes":
case "1":
return true;
case "false":
case "no":
case "0":
return false;
default:
throw new Error("Boolean.parse: Cannot convert string to boolean.");
}
},
'integerArray': function($obj) {
var result = [];
$obj.each(function() {
result.push(parseInt($(this).val()));
});
return result;
}
}
var argument = {};
for (var typeName in availableArgumentList) {
availableArgumentList[typeName].forEach(function(argName) {
var $obj = $('#' + argName);
if ($obj.length == 0) {
$obj = $('.' + argName);
if ($obj.length == 0) {
return;
}
}
argument[argName] = handlerList[typeName]($obj);
});
}
console.log(argument);
reserveTurn(turnList, command, argument);
};
$('#commonSubmit').click(submitAction);
var $colorType = $('#colorType');
if ($colorType.length) {
$colorType.select2({
theme: 'bootstrap4',
placeholder: "색상을 선택해 주세요.",
language: "ko",
containerCss: {
display: "inline-block !important",
color: 'white !important',
},
templateSelection: function(item) {
if (item.disabled) {
return item.text;
}
var bgcolor = item.element.dataset.color;
var fgcolor = item.element.dataset.fontColor;
return $("<span><span style='background-color:{0};color:{1};'> </span>&nbsp;{2}</span>".format(
bgcolor, fgcolor, item.text
));
},
templateResult: function(item) {
if (item.disabled) {
return item.text;
}
var bgcolor = item.element.dataset.color;
var fgcolor = item.element.dataset.fontColor;
return $("<div style='padding: 0.75rem 0.375rem; background-color:{0};color:{1};'>{2}</div>".format(
bgcolor, fgcolor, item.text
));
},
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
dropdownCssClass: 'no-padding simple-select2-align-center bg-secondary text-secondary',
});
}
var $nationType = $('#nationType');
if ($nationType.length) {
$nationType.select2({
theme: 'bootstrap4',
language: "ko",
containerCss: {
display: "inline-block !important",
color: 'white !important',
},
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
});
}
var $destCityID = $('#destCityID');
if ($destCityID.length) {
$destCityID.select2({
theme: 'bootstrap4',
placeholder: "도시를 선택해 주세요.",
language: "ko",
containerCss: {
display: "inline-block !important",
color: 'white !important',
},
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
});
}
var $destNationID = $('#destNationID');
if ($destNationID.length) {
$destNationID.select2({
theme: 'bootstrap4',
placeholder: "국가를 선택해 주세요.",
language: "ko",
containerCss: {
display: "inline-block !important",
color: 'white !important',
},
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
});
}
var $destGeneralID = $('#destGeneralID');
if ($destGeneralID.length) {
$destGeneralID.select2({
theme: 'bootstrap4',
placeholder: "장수를 선택해 주세요.",
language: "ko",
containerCss: {
display: "inline-block !important",
color: 'white !important',
},
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
});
}
var $isGold = $('#isGold');
if ($isGold.length) {
$isGold.select2({
theme: 'bootstrap4',
placeholder: "분량을 지정해 주세요.",
language: "ko",
containerCss: {
display: "inline-block !important",
color: 'white !important',
},
minimumResultsForSearch: -1,
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
});
}
var $amount = $('#amount:not([type=hidden])');
if ($amount.length) {
$amount.select2({
theme: 'bootstrap4',
placeholder: "분량을 지정해 주세요.",
allowClear: false,
language: "ko",
containerCss: {
display: "inline-block !important",
color: 'white !important',
},
tags: true,
sorter: function(items) {
items.sort(function(lhs, rhs) {
return parseInt(lhs.id) - parseInt(rhs.id);
})
return items;
},
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
dropdownCssClass: 'select2-only-number simple-select2-align-center bg-secondary text-secondary',
})
}
$(document).on('keypress', '.select2-only-number .select2-search__field', function() {
$(this).val($(this).val().replace(/[^\d].+/, ""));
if ((event.which < 48 || event.which > 57)) {
event.preventDefault();
}
});
});
+1 -1
View File
@@ -23,7 +23,7 @@ $(function(){
var crewtype = parseInt($parent.data('crewtype'));
calc(crewtype);
$formCrewtype.val(crewtype);
$formAmount.val($this.val());
$formAmount.val($this.val()*100);
if(e.which === 13){
submitAction();
+210
View File
@@ -0,0 +1,210 @@
var templateGeneralCard = '<div class="general_card">\
<h4 class="bg1 with_border"><%generalName%></h4>\
<h4><img src="<%iconPath%>" height=64 width=64></h4><p>\
<%if(leadership){%>\
<%leadership%> / <%strength%> / <%intel%><br>\
<%}%>\
<%if(personalText){%><%personalText%><br><%}%>\
<%if(specialDomesticText||specialWarText){%>\
<%specialDomesticText%> / <%specialWarText%><br>\
<%}%>\
<%if(dex){%><br>\
보병: <%parseInt(dex[0]/1000)%>K<br>\
궁병: <%parseInt(dex[1]/1000)%>K<br>\
기병: <%parseInt(dex[2]/1000)%>K<br>\
귀병: <%parseInt(dex[3]/1000)%>K<br>\
차병: <%parseInt(dex[4]/1000)%>K<br>\
<%}%>\
</p>\
<button type="subject" class="with_skin with_border select_btn" data-name="<%generalName%>" value="<%uniqueName%>" name="pick">선택하기</button>\
</div>';
var templateSpecial =
'<span class="obj_tooltip" data-toggle="tooltip" data-placement="top"><%text%>\
<span class="tooltiptext">\
<%info%>\
</span>\
</span>\
';
function pickGeneral() {
$btn = $(this);
if (hasGeneralID) {
if (!confirm('이 장수를 선택할까요? : {0}'.format($btn.data('name')))) {
return false;
}
$.post({
url: 'j_update_picked_general.php',
dataType: 'json',
data: {
pick: $btn.val()
}
}).then(function(result) {
if (!result.result) {
alert(result.reason);
location.refresh();
}
alert('선택한 장수로 변경했습니다.');
location.href = './';
});
return false;
}
currentGeneralInfo = cards[$btn.val()];
var $card = $btn.closest('.general_card');
var $leftPad = $('#left_pad');
$leftPad.empty();
$card.clone().appendTo($leftPad);
initTooltip($leftPad);
return false;
}
function buildGeneral() {
if (!currentGeneralInfo) {
alert('장수를 선택해주세요!');
return false;
}
if (!confirm('이 장수로 생성할까요?')) {
return false;
}
$.post({
url: 'j_select_picked_general.php',
dataType: 'json',
data: {
pick: currentGeneralInfo.uniqueName,
use_own_picture: $('#use_own_picture').is(':checked'),
leadership: parseInt($('#leadership').val()),
strength: parseInt($('#leadership').val()),
intel: parseInt($('#leadership').val()),
personal: $('#selChar').val()
}
}).then(function(result) {
if (!result.result) {
alert(result.reason);
location.refresh();
}
alert('선택한 장수로 생성했습니다.');
location.href = './';
});
return false;
}
function updateOutdateTimer() {
var $validUntilText = $('#valid_until_text');
var now = Date.now();
var validUntil = $validUntilText.data('until');
if (validUntil <= 0) {
return;
} else if (validUntil < now) {
$validUntilText.data('until', 0);
$('#valid_until').hide();
$('#outdate_token').show();
return;
} else if (validUntil - now <= 30000) {
$validUntilText.css('color', "rgb(255, {0}, {0})".format(255 * (validUntil - now) / 30000));
}
setTimeout(updateOutdateTimer, 1000);
}
function printGenerals(value) {
$('.card_holder').empty();
$('#valid_until').show();
$('#valid_until_text').html(value.validUntil).data('until', (new Date(value.validUntil)).getTime()).css('color', 'white');
$('#outdate_token').hide();
var pick = $.map(value.pick, function(value, key) {
return value;
});
var emptyCard = {
'leadership': null,
'strength': null,
'intel': null,
'personalText': null,
'specialDomesticText': null,
'specialWarText': null,
'dex': null
};
$.each(pick, function(idx, cardData) {
cardData.iconPath = getIconPath(cardData.imgsvr, cardData.picture);
if (cardData.specialDomestic !== undefined) {
cardData.specialDomesticText = TemplateEngine(templateSpecial, {
text: cardData.specialDomesticName,
info: cardData.specialDomesticInfo
});
cardData.specialWarText = '-';
}
if (cardData.specialWar !== undefined) {
cardData.specialWarText = TemplateEngine(templateSpecial, {
text: cardData.specialWarName,
info: cardData.specialWarInfo
});
if (cardData.specialDomesticText === undefined) {
cardData.specialDomesticText = '-';
}
}
//FIXME: ego로 적었던것 같음!
if (cardData.personal in characterInfo) {
cardData.personalText = TemplateEngine(templateSpecial, {
text: characterInfo[cardData.personal].name,
info: characterInfo[cardData.personal].info
});
} else {
cardData.personalText = cardData.personal;
}
cards[cardData.uniqueName] = cardData;
var $card = $(TemplateEngine(templateGeneralCard, $.extend({}, emptyCard, cardData)));
$('.card_holder').append($card);
$card.find('.select_btn').click(pickGeneral);
$card.find('.obj_tooltip').tooltip({
title: function() {
return $.trim($(this).find('.tooltiptext').html());
},
html: true
});
});
updateOutdateTimer();
}
$(function($) {
$.post('j_get_select_pool.php').then(function(value) {
if (!value.result) {
alert(value.reason);
return;
}
console.log(value);
printGenerals(value);
});
if (hasGeneralID) {
$('#create_plate').hide();
}
$('#build_general').on('click', buildGeneral);
$.each(validCustomOption, function(idx, value) {
if (value == 'picture') {
$('.custom_picture').show();
} else if (value == 'ego') {
$('.custom_personality').show();
} else if (value == 'stat') {
$('.custom_stat').show();
}
});
});
+352 -359
View File
@@ -1,360 +1,353 @@
var templateGeneralCard =
'<div class="general_card">\
<h4 class="bg1 with_border"><%name%></h4>\
<h4><img src="<%iconPath%>" height=64 width=64></h4>\
<p><%leadership%> / <%strength%> / <%intel%><br>\
<%nation%><br>\
<%personalText%><br>\
<%specialText%> / <%special2Text%></p>\
<button type="subject" class="with_skin with_border select_btn" data-name="<%name%>" value="<%no%>" name="pick">빙의하기</button>\
<label><input <%keepCnt?"":disabled="disabled"%> type="checkbox" value="<%no%>" name="keep[]" class="keep_select">보관(<%keepCnt%>)</label>\
</div>';
var templateSpecial =
'<span class="obj_tooltip" data-toggle="tooltip" data-placement="top"><%text%>\
<span class="tooltiptext">\
<%info%>\
</span>\
</span>\
';
var templateGeneralRow =
'<tr>\
<td><img class="generalIcon" width="64" height="64" src="<%iconPath%>"></td>\
<td style="<%userCSS%>"><%name%><%nameAux%></td>\
<td><%age%></td>\
<td><%personalWithTooltip%></td>\
<td><%specialDomesticWithTooltip%> / <%speicalWarWithTooltip%></td>\
<td>Lv <%explevel%></td>\
<td><%nation%></td>\
<td><%experience%></td>\
<td><%dedication%></td>\
<td><%officerLevel%></td>\
<td><%total%></td>\
<td><%leadership%></td>\
<td><%strength%></td>\
<td><%intel%></td>\
<td><%killturn%></td>\
</tr>';
function pickGeneral(){
$btn = $(this);
if (!confirm('빙의할까요? : {0}'.format($btn.data('name')))) {
return false;
}
$.post({
url:'j_select_npc.php',
dataType:'json',
data:{
pick:$btn.val()
}
}).then(function(result){
if(!result.result){
alert(result.reason);
location.refresh();
}
alert('빙의에 성공했습니다.');
location.href = './';
});
return false;
}
function updateOutdateTimer(){
var $validUntilText = $('#valid_until_text');
var now = Date.now();
var validUntil = $validUntilText.data('until');
if(validUntil <= 0){
return;
}
else if(validUntil < now){
$validUntilText.data('until',0);
$('#valid_until').hide();
$('#outdate_token').show();
return;
}
else if(validUntil - now <= 30000){
$validUntilText.css('color', "rgb(255, {0}, {0})".format(255*(validUntil - now)/30000));
}
setTimeout(updateOutdateTimer, 1000);
}
function updatePickMoreTimer(){
var $btn = $('#btn_pick_more');
var now = Date.now();
var remain = ($btn.data('available') - now) / 1000;
if(remain <= 0){
$btn.prop('disabled', false)
$btn.html('다른 장수 보기');
return;
}
$btn.html('다른 장수 보기({0}초)'.format(Math.ceil(remain)));
setTimeout(updatePickMoreTimer, 250);
}
function printGenerals(value){
$('.card_holder').empty();
$('#valid_until').show();
$('#valid_until_text').html(value.validUntil).data('until', (new Date(value.validUntil)).getTime()).css('color','white');
$('#outdate_token').hide();
var time = Date.now() + value.pickMoreSeconds*1000;
$('#btn_pick_more').data('available', time).prop('disabled',true);
var pick = $.map(value.pick, function(value, key) {
return value;
});
pick.sort(function(lhs, rhs){
var lsum = lhs.leadership+lhs.strength+lhs.intel;
var rsum = rhs.leadership+rhs.strength+rhs.intel;
return lsum - rsum;
});
$.each(pick, function(idx, cardData){
cardData.iconPath = getIconPath(cardData.imgsvr, cardData.picture);
if(cardData.special in specialInfo){
cardData.specialText = TemplateEngine(templateSpecial, {
text:cardData.special,
info:specialInfo[cardData.special]
});
}
else{
cardData.specialText = cardData.special;
}
if(cardData.special2 in specialInfo){
cardData.special2Text = TemplateEngine(templateSpecial, {
text:cardData.special2,
info:specialInfo[cardData.special2]
});
}
else{
cardData.special2Text = cardData.special2;
}
if(cardData.personal in characterInfo){
cardData.personalText = TemplateEngine(templateSpecial, {
text:cardData.personal,
info:characterInfo[cardData.personal]
});
}
else{
cardData.personalText = cardData.personal;
}
var $card = $(TemplateEngine(templateGeneralCard, cardData));
$('.card_holder').append($card);
$card.find('.select_btn').click(pickGeneral);
$card.find('.obj_tooltip').tooltip({
title:function(){
return $.trim($(this).find('.tooltiptext').html());
},
html:true
});
});
updatePickMoreTimer();
updateOutdateTimer();
}
function printGeneralList(value){
var tokenList = value.token;
var generalList = $.map(value.list, function(general){
general = {
no:general[0],
picture:general[1],
imgsvr:general[2],
npc:general[3],
age:general[4],
nation:general[5],
special:general[6],
special2:general[7],
personal:general[8],
name:general[9],
ownerName:general[10],
injury:general[11],
leadership:general[12],
lbonus:general[13],
strength:general[14],
intel:general[15],
explevel:general[16],
experience:general[17],
dedication:general[18],
officerLevel:general[19],
killturn:general[20],
connect:general[21],
reserved:0
};
if(general.npc < 2){
general.reserved = 2;
}
if(general.no in tokenList){
general.reserved = 1;
}
general.userCSS = "";
general.nameAux = "";
if(general.reserved == 1){
general.userCSS = 'color:violet';
}
else if(general.npc >= 2){
general.userCSS = 'color:cyan';
}
else if(general.npc == 1){
general.userCSS = 'color:skyblue';
}
if(general.ownerName){
general.nameAux += '<br><small>({0})</small>'.format(general.ownerName);
}
if(general.reserved == 1){
general.nameAux += '<br><small>({0}회)</small>'.format(tokenList[general.no]);
}
general.total = general.leadership + general.strength + general.intel;
general.iconPath = getIconPath(general.imgsvr, general.picture);
general.specialDomesticWithTooltip = TemplateEngine(templateSpecial, {
text:general.special,
info:specialInfo[general.special]
});
general.speicalWarWithTooltip = TemplateEngine(templateSpecial, {
text:general.special2,
info:specialInfo[general.special2]
});
general.personalWithTooltip = TemplateEngine(templateSpecial, {
text:general.personal,
info:characterInfo[general.personal]
});
return general;
});
generalList.sort(function(lhs, rhs){
if(lhs.reserved > rhs.reserved){
return -1;
}
if(lhs.reserved < rhs.reserved){
return 1;
}
if(lhs.total != rhs.total){
return rhs.total - lhs.total;
}
if(lhs.leadership != rhs.leadership){
return rhs.leadership - lhs.total;
}
if(lhs.name < rhs.name){
return -1;
}
if(lhs.name > rhs.name){
return 1;
}
return 0;
});
window.generalList = generalList;
_printGeneralList(true);
}
function _printGeneralList(clear){
var $generalTable = $('#general_list');
if(clear){
$generalTable.empty();
$generalTable.data('lastIdx', 0);
$('#row_print_more').show();
}
generalList = window.generalList;
var idxFrom = $generalTable.data('lastIdx');
var idxTo = Math.min(idxFrom + 50, generalList.length);
$generalTable.data('lastIdx', idxTo);
for(var idx = idxFrom; idx < idxFrom + 50; idx++){
var general = generalList[idx];
$generalTable.append(TemplateEngine(templateGeneralRow, general));
}
if(idxTo == generalList.length){
$('#row_print_more').hide();
}
$generalTable.find('.obj_tooltip').tooltip({
title:function(){
return $.trim($(this).find('.tooltiptext').html());
},
html:true
});
$('#tb_general_list').show();
}
$(function($){
window.generalList = [];
$.post('j_get_select_npc_token.php').then(function(value){
if(!value.result){
alert(value.reason);
return;
}
console.log(value);
printGenerals(value);
});
$('#btn_pick_more').click(function(){
var generals = $.map($('.keep_select:checked'), function(value){
return $(value).val();
});
console.log(generals);
$.post({
url:'j_get_select_npc_token.php',
dataType:'json',
data:{
refresh:true,
keep:generals
}
}).then(function(result){
if(!result.result){
alert(result.reason);
location.refresh();
}
console.log(result);
printGenerals(result);
});
});
$('#btn_load_general_list').click(function(){
$.post({
url:'j_get_general_list.php',
dataType:'json',
data:{
with_token:true
}
}).then(function(result){
if(!result.result){
alert(result.reason);
return false;
}
printGeneralList(result);
});
});
$('#btn_print_more').click(function(){
_printGeneralList();
})
var templateGeneralCard =
'<div class="general_card">\
<h4 class="bg1 with_border"><%name%></h4>\
<h4><img src="<%iconPath%>" height=64 width=64></h4>\
<p><%leadership%> / <%strength%> / <%intel%><br>\
<%nation%><br>\
<%personalText%><br>\
<%specialText%> / <%special2Text%></p>\
<button type="subject" class="with_skin with_border select_btn" data-name="<%name%>" value="<%no%>" name="pick">빙의하기</button>\
<label><input <%keepCnt?"":disabled="disabled"%> type="checkbox" value="<%no%>" name="keep[]" class="keep_select">보관(<%keepCnt%>)</label>\
</div>';
var templateSpecial =
'<span class="obj_tooltip" data-toggle="tooltip" data-placement="top"><%text%>\
<span class="tooltiptext">\
<%info%>\
</span>\
</span>\
';
var templateGeneralRow =
'<tr>\
<td><img class="generalIcon" width="64" height="64" src="<%iconPath%>"></td>\
<td style="<%userCSS%>"><%name%><%nameAux%></td>\
<td><%age%></td>\
<td><%personalWithTooltip%></td>\
<td><%specialDomesticWithTooltip%> / <%speicalWarWithTooltip%></td>\
<td>Lv <%explevel%></td>\
<td><%nation%></td>\
<td><%experience%></td>\
<td><%dedication%></td>\
<td><%officerLevel%></td>\
<td><%total%></td>\
<td><%leadership%></td>\
<td><%strength%></td>\
<td><%intel%></td>\
<td><%killturn%></td>\
</tr>';
function pickGeneral() {
$btn = $(this);
if (!confirm('빙의할까요? : {0}'.format($btn.data('name')))) {
return false;
}
$.post({
url: 'j_select_npc.php',
dataType: 'json',
data: {
pick: $btn.val()
}
}).then(function(result) {
if (!result.result) {
alert(result.reason);
location.refresh();
}
alert('빙의에 성공했습니다.');
location.href = './';
});
return false;
}
function updateOutdateTimer() {
var $validUntilText = $('#valid_until_text');
var now = Date.now();
var validUntil = $validUntilText.data('until');
if (validUntil <= 0) {
return;
} else if (validUntil < now) {
$validUntilText.data('until', 0);
$('#valid_until').hide();
$('#outdate_token').show();
return;
} else if (validUntil - now <= 30000) {
$validUntilText.css('color', "rgb(255, {0}, {0})".format(255 * (validUntil - now) / 30000));
}
setTimeout(updateOutdateTimer, 1000);
}
function updatePickMoreTimer() {
var $btn = $('#btn_pick_more');
var now = Date.now();
var remain = ($btn.data('available') - now) / 1000;
if (remain <= 0) {
$btn.prop('disabled', false)
$btn.html('다른 장수 보기');
return;
}
$btn.html('다른 장수 보기({0}초)'.format(Math.ceil(remain)));
setTimeout(updatePickMoreTimer, 250);
}
function printGenerals(value) {
$('.card_holder').empty();
$('#valid_until').show();
$('#valid_until_text').html(value.validUntil).data('until', (new Date(value.validUntil)).getTime()).css('color', 'white');
$('#outdate_token').hide();
var time = Date.now() + value.pickMoreSeconds * 1000;
$('#btn_pick_more').data('available', time).prop('disabled', true);
var pick = $.map(value.pick, function(value, key) {
return value;
});
pick.sort(function(lhs, rhs) {
var lsum = lhs.leadership + lhs.strength + lhs.intel;
var rsum = rhs.leadership + rhs.strength + rhs.intel;
return lsum - rsum;
});
$.each(pick, function(idx, cardData) {
cardData.iconPath = getIconPath(cardData.imgsvr, cardData.picture);
if (cardData.special in specialInfo) {
cardData.specialText = TemplateEngine(templateSpecial, {
text: cardData.special,
info: specialInfo[cardData.special]
});
} else {
cardData.specialText = cardData.special;
}
if (cardData.special2 in specialInfo) {
cardData.special2Text = TemplateEngine(templateSpecial, {
text: cardData.special2,
info: specialInfo[cardData.special2]
});
} else {
cardData.special2Text = cardData.special2;
}
if (cardData.personal in characterInfo) {
cardData.personalText = TemplateEngine(templateSpecial, {
text: cardData.personal,
info: characterInfo[cardData.personal]
});
} else {
cardData.personalText = cardData.personal;
}
var $card = $(TemplateEngine(templateGeneralCard, cardData));
$('.card_holder').append($card);
$card.find('.select_btn').click(pickGeneral);
$card.find('.obj_tooltip').tooltip({
title: function() {
return $.trim($(this).find('.tooltiptext').html());
},
html: true
});
});
updatePickMoreTimer();
updateOutdateTimer();
}
function printGeneralList(value) {
var tokenList = value.token;
var generalList = $.map(value.list, function(general) {
general = {
no: general[0],
picture: general[1],
imgsvr: general[2],
npc: general[3],
age: general[4],
nation: general[5],
special: general[6],
special2: general[7],
personal: general[8],
name: general[9],
ownerName: general[10],
injury: general[11],
leadership: general[12],
lbonus: general[13],
strength: general[14],
intel: general[15],
explevel: general[16],
experience: general[17],
dedication: general[18],
officerLevel: general[19],
killturn: general[20],
connect: general[21],
reserved: 0
};
if (general.npc < 2) {
general.reserved = 2;
}
if (general.no in tokenList) {
general.reserved = 1;
}
general.userCSS = "";
general.nameAux = "";
if (general.reserved == 1) {
general.userCSS = 'color:violet';
} else if (general.npc >= 2) {
general.userCSS = 'color:cyan';
} else if (general.npc == 1) {
general.userCSS = 'color:skyblue';
}
if (general.ownerName) {
general.nameAux += '<br><small>({0})</small>'.format(general.ownerName);
}
if (general.reserved == 1) {
general.nameAux += '<br><small>({0}회)</small>'.format(tokenList[general.no]);
}
general.total = general.leadership + general.strength + general.intel;
general.iconPath = getIconPath(general.imgsvr, general.picture);
general.specialDomesticWithTooltip = TemplateEngine(templateSpecial, {
text: general.special,
info: specialInfo[general.special]
});
general.speicalWarWithTooltip = TemplateEngine(templateSpecial, {
text: general.special2,
info: specialInfo[general.special2]
});
general.personalWithTooltip = TemplateEngine(templateSpecial, {
text: general.personal,
info: characterInfo[general.personal]
});
return general;
});
generalList.sort(function(lhs, rhs) {
if (lhs.reserved > rhs.reserved) {
return -1;
}
if (lhs.reserved < rhs.reserved) {
return 1;
}
if (lhs.total != rhs.total) {
return rhs.total - lhs.total;
}
if (lhs.leadership != rhs.leadership) {
return rhs.leadership - lhs.total;
}
if (lhs.name < rhs.name) {
return -1;
}
if (lhs.name > rhs.name) {
return 1;
}
return 0;
});
window.generalList = generalList;
_printGeneralList(true);
}
function _printGeneralList(clear) {
var $generalTable = $('#general_list');
if (clear) {
$generalTable.empty();
$generalTable.data('lastIdx', 0);
$('#row_print_more').show();
}
generalList = window.generalList;
var idxFrom = $generalTable.data('lastIdx');
var idxTo = Math.min(idxFrom + 50, generalList.length);
$generalTable.data('lastIdx', idxTo);
for (var idx = idxFrom; idx < idxFrom + 50; idx++) {
var general = generalList[idx];
$generalTable.append(TemplateEngine(templateGeneralRow, general));
}
if (idxTo == generalList.length) {
$('#row_print_more').hide();
}
$generalTable.find('.obj_tooltip').tooltip({
title: function() {
return $.trim($(this).find('.tooltiptext').html());
},
html: true
});
$('#tb_general_list').show();
}
$(function($) {
window.generalList = [];
$.post('j_get_select_npc_token.php').then(function(value) {
if (!value.result) {
alert(value.reason);
return;
}
console.log(value);
printGenerals(value);
});
$('#btn_pick_more').click(function() {
var generals = $.map($('.keep_select:checked'), function(value) {
return $(value).val();
});
console.log(generals);
$.post({
url: 'j_get_select_npc_token.php',
dataType: 'json',
data: {
refresh: true,
keep: generals
}
}).then(function(result) {
if (!result.result) {
alert(result.reason);
location.refresh();
}
console.log(result);
printGenerals(result);
});
});
$('#btn_load_general_list').click(function() {
$.post({
url: 'j_get_general_list.php',
dataType: 'json',
data: {
with_token: true
}
}).then(function(result) {
if (!result.result) {
alert(result.reason);
return false;
}
printGeneralList(result);
});
});
$('#btn_print_more').click(function() {
_printGeneralList();
})
});
+74 -57
View File
@@ -1,57 +1,74 @@
<?php
namespace sammo;
/** @var \Composer\Autoload\ClassLoader $loader */
$loader = require __DIR__.'/../vendor/autoload.php';
$loader->addPsr4('sammo\\', __DIR__.'/sammo', true);
$loader->addClassMap((function () {
$d_settingMap = [];
foreach (glob(__DIR__.'/d_setting/*.orig.php') as $filepath) {
$filepath = str_replace('.orig.php', '.php', $filepath);
$filename = basename($filepath);
$classname = explode('.', $filename)[0];
$d_settingMap['sammo\\'.$classname] = $filepath;
};
return $d_settingMap;
})());
//디버그용 매크로
ini_set("session.cache_expire", 10080); // minutes
// 각종 변수
define('STEP_LOG', true);
define('PROCESS_LOG', true);
ob_start();
// 에러 메세지 출력
function Error($message='', $url="")
{
if (!$url) {
$url = $_SERVER['REQUEST_URI'];
}
$e = new \Exception();
logError("aux_err", $message, '', getExceptionTraceAsString($e));
$templates = new \League\Plates\Engine(__DIR__.'/templates');
ob_get_flush();
WebUtil::setHeaderNoCache();
die($templates->render('error', [
'message' => $message
]));
}
function MessageBox($str)
{
echo "<script>alert('$str');</script>";
}
function LogText($prefix, $variable)
{
$text = sprintf('%s : %s'."\r\n", $prefix, TVarDumper::dump($variable));
file_put_contents(ROOT.'/d_log/'.UniqueConst::$serverName.'_dbg_logs.txt', $text, FILE_APPEND);
}
<?php
namespace sammo;
/** @var \Composer\Autoload\ClassLoader $loader */
$loader = require __DIR__.'/../vendor/autoload.php';
$loader->addPsr4('sammo\\', __DIR__.'/sammo', true);
$loader->addClassMap((function () {
$d_settingMap = [];
foreach (glob(__DIR__.'/d_setting/*.orig.php') as $filepath) {
$filepath = str_replace('.orig.php', '.php', $filepath);
$filename = basename($filepath);
$classname = explode('.', $filename)[0];
$d_settingMap['sammo\\'.$classname] = $filepath;
};
return $d_settingMap;
})());
//디버그용 매크로
ini_set("session.cache_expire", 10080); // minutes
// 각종 변수
define('STEP_LOG', true);
define('PROCESS_LOG', true);
ob_start();
// 에러 메세지 출력
function Error($message='', $url="")
{
if (!$url) {
$url = $_SERVER['REQUEST_URI'];
}
$e = new \Exception();
logError("aux_err", $message, '', getExceptionTraceAsString($e));
$templates = new \League\Plates\Engine(__DIR__.'/templates');
ob_get_flush();
WebUtil::setHeaderNoCache();
die($templates->render('error', [
'message' => $message
]));
}
function MessageBox($str)
{
echo "<script>alert('$str');</script>";
}
function LogText($prefix, $variable)
{
$text = sprintf('%s : %s'."\r\n", $prefix, TVarDumper::dump($variable));
file_put_contents(ROOT.'/d_log/'.UniqueConst::$serverName.'_dbg_logs.txt', $text, FILE_APPEND);
}
function prepareDir(string $dirPath, bool $forceCreate=true):bool{
if(file_exists($dirPath)){
if(is_dir($dirPath)){
return true;
}
if(!$forceCreate){
throw new \RuntimeException('이미 파일이 있습니다');
}
if(!unlink($dirPath)){
return false;
}
return mkdir($dirPath);
}
return mkdir($dirPath, 0777, true);
}
+19 -5
View File
@@ -43,7 +43,7 @@ function processWar(General $attackerGeneral, array $rawAttackerNation, array $r
$iterDefender = new \ArrayIterator($defenderList);
$iterDefender->rewind();
$getNextDefender = function(?WarUnit $prevDefender, bool $reqNext) use ($iterDefender, $rawDefenderNation, $db) {
$getNextDefender = function(?WarUnit $prevDefender, bool $reqNext) use ($iterDefender, $rawDefenderNation, $rawDefenderCity, $db) {
if($prevDefender !== null){
$prevDefender->applyDB($db);
}
@@ -57,6 +57,7 @@ function processWar(General $attackerGeneral, array $rawAttackerNation, array $r
}
$nextDefender = $iterDefender->current();
$nextDefender->setRawCity($rawDefenderCity);
if(extractBattleOrder($nextDefender) <= 0){
return null;
}
@@ -260,6 +261,15 @@ function processWar_NG(
$attacker->addTrain(1);
$defender->addTrain(1);
$attackerCrewTypeCoef = $attacker->getCrewType()->getAttackCoef($defender->getCrewType()) * $defender->getCrewType()->getDefenceCoef($attacker->getCrewType());
$defenderCrewTypeCoef = $defender->getCrewType()->getAttackCoef($attacker->getCrewType()) * $attacker->getCrewType()->getDefenceCoef($defender->getCrewType());
if($attackerCrewTypeCoef > $defenderCrewTypeCoef && $attacker instanceof WarUnitGeneral){
$attacker->getGeneral()->increaseInheritancePoint('snipe_combat', 1);
}
if($defenderCrewTypeCoef > $attackerCrewTypeCoef && $defender instanceof WarUnitGeneral){
$defender->getGeneral()->increaseInheritancePoint('snipe_combat', 1);
}
$attackerName = $attacker->getName();
$attackerCrewTypeName = $attacker->getCrewTypeName();
@@ -521,7 +531,7 @@ function ConquerCity(array $admin, General $general, array $city) {
$lord = new General($db->queryFirstRow(
'SELECT %l FROM general WHERE nation = %i AND officer_level = %i LIMIT 1',
Util::formatListOfBackticks(General::mergeQueryColumn(['npc', 'gold', 'rice', 'experience', 'explevel', 'dedication', 'dedlevel', 'aux'], 1)[0]),
Util::formatListOfBackticks(General::mergeQueryColumn(['npc', 'gold', 'rice', 'experience', 'explevel', 'belong', 'dedication', 'dedlevel', 'aux'], 1)[0]),
$defenderNationID,
12
), null, $city, $loseNation, $year, $month, false);
@@ -558,13 +568,17 @@ function ConquerCity(array $admin, General $general, array $city) {
}
}
//NPC인 경우 10% 확률로 임관(엔장, 인재, 의병)
//NPC인 경우 일정 확률로 임관(엔장, 인재, 의병)
$npcType = $oldGeneral->getNPCType();
if($admin['join_mode'] != 'onlyRandom' && 2 <= $npcType && $npcType <= 8 && $npcType != 5 && Util::randBool(0.1)) {
if($admin['join_mode'] != 'onlyRandom' && 2 <= $npcType && $npcType <= 8 && $npcType != 5 && Util::randBool(GameConst::$joinRuinedNPCProp)) {
$cmd = buildGeneralCommandClass('che_임관', $oldGeneral, $admin, [
'destNationID'=>$attackerNationID
]);
_setGeneralCommand($cmd, [0]);
$joinTurn = Util::randRangeInt(0, 12);
if($joinTurn){
_setGeneralCommand(buildGeneralCommandClass('che_견문', $oldGeneral, $admin), iterator_to_array(Util::range($joinTurn)));
}
_setGeneralCommand($cmd, [$joinTurn]);
}
}
+4
View File
@@ -0,0 +1,4 @@
<?php
require('../vendor/autoload.php');
//ParsedownExtra;

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