From 4064156a2255f78efa4f7d5b71b32068f776c9b0 Mon Sep 17 00:00:00 2001
From: rolevax
Date: Sat, 30 Jun 2018 18:34:46 +0800
Subject: [PATCH] move doc index to home page
---
Gemfile.lock | 149 +++++++++---------
_config.yml | 3 -
_data/abbr.yml | 132 ++++++++++++++++
_data/lua-api.yml | 213 ++++++++++++++++++++++---
_data/lua-callbacks.yml | 53 +++++++
bugging.md | 8 +-
contribute.md | 3 +-
docs/abbr.md | 27 ++++
docs/cpp-note.md | 6 +-
docs/cpp.md | 2 +-
docs/dev-setup.md | 98 +++++++-----
docs/editor/api.md | 108 ++++++++-----
docs/editor/flow.md | 190 +++++++++++++++++++++++
docs/editor/func.md | 238 ++++++++++++++++++++++++++--
docs/editor/local.md | 335 ++++++++++++++++++++++++++++++++++++++++
docs/editor/start.md | 14 +-
docs/editor/userdata.md | 208 +++++++++++++++++++++++++
docs/editor/var.md | 5 +-
docs/girl.md | 47 +++---
docs/libsaki/mount.md | 2 +-
docs/phil.md | 3 +-
docs/rule.md | 8 +-
docs/start.md | 37 ++---
feedback.md | 2 -
index.md | 106 +++++++++----
signup-pass.md | 2 +-
signup.md | 4 +-
27 files changed, 1711 insertions(+), 292 deletions(-)
create mode 100644 _data/abbr.yml
create mode 100644 _data/lua-callbacks.yml
create mode 100644 docs/abbr.md
create mode 100644 docs/editor/flow.md
create mode 100644 docs/editor/local.md
create mode 100644 docs/editor/userdata.md
diff --git a/Gemfile.lock b/Gemfile.lock
index 0a48f64..d6874aa 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
GEM
remote: https://rubygems.org/
specs:
- activesupport (4.2.9)
+ activesupport (4.2.10)
i18n (~> 0.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
@@ -13,90 +13,99 @@ GEM
execjs
coffee-script-source (1.11.1)
colorator (1.1.0)
- commonmarker (0.17.9)
+ commonmarker (0.17.11)
ruby-enum (~> 0.5)
concurrent-ruby (1.0.5)
+ dnsruby (1.61.2)
+ addressable (~> 2.5)
+ em-websocket (0.5.1)
+ eventmachine (>= 0.12.9)
+ http_parser.rb (~> 0.6.0)
ethon (0.11.0)
ffi (>= 1.3.0)
+ eventmachine (1.2.7)
execjs (2.7.0)
- faraday (0.14.0)
+ faraday (0.15.2)
multipart-post (>= 1.2, < 3)
- ffi (1.9.23)
+ ffi (1.9.25)
forwardable-extended (2.6.0)
gemoji (3.0.0)
- github-pages (179)
- activesupport (= 4.2.9)
- github-pages-health-check (= 1.4.0)
- jekyll (= 3.6.2)
- jekyll-avatar (= 0.5.0)
+ github-pages (191)
+ activesupport (= 4.2.10)
+ github-pages-health-check (= 1.8.1)
+ jekyll (= 3.7.3)
+ jekyll-avatar (= 0.6.0)
jekyll-coffeescript (= 1.1.1)
jekyll-commonmark-ghpages (= 0.1.5)
jekyll-default-layout (= 0.1.4)
- jekyll-feed (= 0.9.3)
+ jekyll-feed (= 0.10.0)
jekyll-gist (= 1.5.0)
jekyll-github-metadata (= 2.9.4)
- jekyll-mentions (= 1.3.0)
+ jekyll-mentions (= 1.4.1)
jekyll-optional-front-matter (= 0.3.0)
jekyll-paginate (= 1.1.0)
jekyll-readme-index (= 0.2.0)
- jekyll-redirect-from (= 0.13.0)
+ jekyll-redirect-from (= 0.14.0)
jekyll-relative-links (= 0.5.3)
- jekyll-remote-theme (= 0.2.3)
+ jekyll-remote-theme (= 0.3.1)
jekyll-sass-converter (= 1.5.2)
- jekyll-seo-tag (= 2.4.0)
+ jekyll-seo-tag (= 2.5.0)
jekyll-sitemap (= 1.2.0)
jekyll-swiss (= 0.4.0)
- jekyll-theme-architect (= 0.1.0)
- jekyll-theme-cayman (= 0.1.0)
- jekyll-theme-dinky (= 0.1.0)
- jekyll-theme-hacker (= 0.1.0)
- jekyll-theme-leap-day (= 0.1.0)
- jekyll-theme-merlot (= 0.1.0)
- jekyll-theme-midnight (= 0.1.0)
- jekyll-theme-minimal (= 0.1.0)
- jekyll-theme-modernist (= 0.1.0)
- jekyll-theme-primer (= 0.5.2)
- jekyll-theme-slate (= 0.1.0)
- jekyll-theme-tactile (= 0.1.0)
- jekyll-theme-time-machine (= 0.1.0)
+ jekyll-theme-architect (= 0.1.1)
+ jekyll-theme-cayman (= 0.1.1)
+ jekyll-theme-dinky (= 0.1.1)
+ jekyll-theme-hacker (= 0.1.1)
+ jekyll-theme-leap-day (= 0.1.1)
+ jekyll-theme-merlot (= 0.1.1)
+ jekyll-theme-midnight (= 0.1.1)
+ jekyll-theme-minimal (= 0.1.1)
+ jekyll-theme-modernist (= 0.1.1)
+ jekyll-theme-primer (= 0.5.3)
+ jekyll-theme-slate (= 0.1.1)
+ jekyll-theme-tactile (= 0.1.1)
+ jekyll-theme-time-machine (= 0.1.1)
jekyll-titles-from-headings (= 0.5.1)
- jemoji (= 0.9.0)
- kramdown (= 1.16.2)
+ jemoji (= 0.10.1)
+ kramdown (= 1.17.0)
liquid (= 4.0.0)
listen (= 3.1.5)
mercenary (~> 0.3)
- minima (= 2.4.0)
- nokogiri (>= 1.8.1, < 2.0)
+ minima (= 2.5.0)
+ nokogiri (>= 1.8.2, < 2.0)
rouge (= 2.2.1)
terminal-table (~> 1.4)
- github-pages-health-check (1.4.0)
+ github-pages-health-check (1.8.1)
addressable (~> 2.3)
- net-dns (~> 0.8)
+ dnsruby (~> 1.60)
octokit (~> 4.0)
public_suffix (~> 2.0)
typhoeus (~> 1.3)
- html-pipeline (2.7.1)
+ html-pipeline (2.8.4)
activesupport (>= 2)
nokogiri (>= 1.4)
+ http_parser.rb (0.6.0)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
- jekyll (3.6.2)
+ jekyll (3.7.3)
addressable (~> 2.4)
colorator (~> 1.0)
+ em-websocket (~> 0.5)
+ i18n (~> 0.7)
jekyll-sass-converter (~> 1.0)
- jekyll-watch (~> 1.1)
+ jekyll-watch (~> 2.0)
kramdown (~> 1.14)
liquid (~> 4.0)
mercenary (~> 0.3.3)
pathutil (~> 0.9)
- rouge (>= 1.7, < 3)
+ rouge (>= 1.7, < 4)
safe_yaml (~> 1.0)
- jekyll-avatar (0.5.0)
+ jekyll-avatar (0.6.0)
jekyll (~> 3.0)
jekyll-coffeescript (1.1.1)
coffee-script (~> 2.2)
coffee-script-source (~> 1.11.1)
- jekyll-commonmark (1.1.0)
+ jekyll-commonmark (1.2.0)
commonmarker (~> 0.14)
jekyll (>= 3.0, < 4.0)
jekyll-commonmark-ghpages (0.1.5)
@@ -105,15 +114,14 @@ GEM
rouge (~> 2)
jekyll-default-layout (0.1.4)
jekyll (~> 3.0)
- jekyll-feed (0.9.3)
+ jekyll-feed (0.10.0)
jekyll (~> 3.3)
jekyll-gist (1.5.0)
octokit (~> 4.2)
jekyll-github-metadata (2.9.4)
jekyll (~> 3.1)
octokit (~> 4.0, != 4.4.0)
- jekyll-mentions (1.3.0)
- activesupport (~> 4.0)
+ jekyll-mentions (1.4.1)
html-pipeline (~> 2.3)
jekyll (~> 3.0)
jekyll-optional-front-matter (0.3.0)
@@ -121,71 +129,69 @@ GEM
jekyll-paginate (1.1.0)
jekyll-readme-index (0.2.0)
jekyll (~> 3.0)
- jekyll-redirect-from (0.13.0)
+ jekyll-redirect-from (0.14.0)
jekyll (~> 3.3)
jekyll-relative-links (0.5.3)
jekyll (~> 3.3)
- jekyll-remote-theme (0.2.3)
+ jekyll-remote-theme (0.3.1)
jekyll (~> 3.5)
rubyzip (>= 1.2.1, < 3.0)
- typhoeus (>= 0.7, < 2.0)
jekyll-sass-converter (1.5.2)
sass (~> 3.4)
- jekyll-seo-tag (2.4.0)
+ jekyll-seo-tag (2.5.0)
jekyll (~> 3.3)
jekyll-sitemap (1.2.0)
jekyll (~> 3.3)
jekyll-swiss (0.4.0)
- jekyll-theme-architect (0.1.0)
+ jekyll-theme-architect (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-cayman (0.1.0)
+ jekyll-theme-cayman (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-dinky (0.1.0)
+ jekyll-theme-dinky (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-hacker (0.1.0)
+ jekyll-theme-hacker (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-leap-day (0.1.0)
+ jekyll-theme-leap-day (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-merlot (0.1.0)
+ jekyll-theme-merlot (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-midnight (0.1.0)
+ jekyll-theme-midnight (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-minimal (0.1.0)
+ jekyll-theme-minimal (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-modernist (0.1.0)
+ jekyll-theme-modernist (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-primer (0.5.2)
+ jekyll-theme-primer (0.5.3)
jekyll (~> 3.5)
jekyll-github-metadata (~> 2.9)
- jekyll-seo-tag (~> 2.2)
- jekyll-theme-slate (0.1.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-slate (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-tactile (0.1.0)
+ jekyll-theme-tactile (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-time-machine (0.1.0)
+ jekyll-theme-time-machine (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-titles-from-headings (0.5.1)
jekyll (~> 3.3)
- jekyll-watch (1.5.1)
+ jekyll-watch (2.0.0)
listen (~> 3.0)
- jemoji (0.9.0)
- activesupport (~> 4.0, >= 4.2.9)
+ jemoji (0.10.1)
gemoji (~> 3.0)
html-pipeline (~> 2.2)
jekyll (~> 3.0)
- kramdown (1.16.2)
+ kramdown (1.17.0)
libv8 (3.16.14.19)
liquid (4.0.0)
listen (3.1.5)
@@ -194,16 +200,15 @@ GEM
ruby_dep (~> 1.2)
mercenary (0.3.6)
mini_portile2 (2.3.0)
- minima (2.4.0)
+ minima (2.5.0)
jekyll (~> 3.5)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
minitest (5.11.3)
multipart-post (2.0.0)
- net-dns (0.8.0)
- nokogiri (1.8.2)
+ nokogiri (1.8.4)
mini_portile2 (~> 2.3.0)
- octokit (4.8.0)
+ octokit (4.10.0)
sawyer (~> 0.8.0, >= 0.5.3)
pathutil (0.16.1)
forwardable-extended (~> 2.6)
@@ -218,7 +223,7 @@ GEM
ruby_dep (1.5.0)
rubyzip (1.2.1)
safe_yaml (1.0.4)
- sass (3.5.5)
+ sass (3.5.7)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
@@ -236,7 +241,7 @@ GEM
ethon (>= 0.9.0)
tzinfo (1.2.5)
thread_safe (~> 0.1)
- unicode-display_width (1.3.0)
+ unicode-display_width (1.4.0)
PLATFORMS
ruby
@@ -249,7 +254,7 @@ DEPENDENCIES
tzinfo-data
RUBY VERSION
- ruby 2.5.0p0
+ ruby 2.5.1p57
BUNDLED WITH
- 1.16.1
+ 1.16.4
diff --git a/_config.yml b/_config.yml
index b52513b..0cb02c0 100644
--- a/_config.yml
+++ b/_config.yml
@@ -7,10 +7,7 @@ baseurl: ""
url: ""
github_username: rolevax
header_pages:
- - docs.md
- feedback.md
- - contribute.md
- - crowd.md
webrick:
headers:
Access-Control-Allow-Origin: "*"
diff --git a/_data/abbr.yml b/_data/abbr.yml
new file mode 100644
index 0000000..396a2e2
--- /dev/null
+++ b/_data/abbr.yml
@@ -0,0 +1,132 @@
+-
+ abbr: ct
+ full: count
+ desc: 计数、个数
+-
+ abbr: num
+ full: number
+ desc: 个数、号码
+-
+ abbr: s11n
+ full: serialization
+-
+ abbr: i18n
+ full: internationalization
+-
+ abbr: impl
+ full: implementation
+-
+ abbr: pimpl
+ full: pointer to implementation
+-
+ abbr: ptr
+ full: pointer
+-
+ abbr: ref
+ full: reference
+-
+ abbr: res
+ full: result
+-
+ abbr: iff
+ full: if and only if
+-
+ abbr: str
+ full: string
+-
+ abbr: err
+ full: error
+-
+ abbr: expr
+ full: expression
+-
+ abbr: stmt
+ full: statement
+-
+ abbr: cmd
+ full: command
+-
+ abbr: msg
+ full: message
+-
+ abbr: regex
+ full: regular expression
+-
+ abbr: uid
+ full: user ID
+-
+ abbr: func
+ full: function
+-
+ abbr: dir
+ full: directory
+-
+ abbr: tan90
+ full: does not exist
+-
+ abbr: iter
+ full: iterator, iteration
+-
+ abbr: val
+ full: value
+-
+ abbr: var
+ full: variable
+-
+ abbr: prev
+ full: previous
+-
+ abbr: indic
+ full: indicator
+-
+ abbr: perm
+ full: permutation
+-
+ abbr: seq
+ full: sequence
+-
+ abbr: inc
+ full: increase
+-
+ abbr: eff
+ full: effect, effective
+-
+ abbr: arg
+ full: argument
+-
+ abbr: param
+ full: parameter
+-
+ abbr: init
+ full: initialize
+-
+ abbr: ctrl
+ full: control, controller
+-
+ abbr: ctx
+ full: context
+-
+ abbr: cp
+ full: chii or pon
+-
+ abbr: dmk
+ full: daiminkan
+-
+ abbr: cpdmk
+ full: chii, pon, or daiminkan
+-
+ abbr: irs
+ full: in-round skill
+-
+ abbr: ors
+ full: out-of-round skill
+-
+ abbr: drid
+ full: dora indicator
+-
+ abbr: urid
+ full: uradora indicator
+-
+ abbr: desc
+ full: description
+
diff --git a/_data/lua-api.yml b/_data/lua-api.yml
index 34162a1..37e3488 100644
--- a/_data/lua-api.yml
+++ b/_data/lua-api.yml
@@ -3,23 +3,18 @@
members:
-
name: "构造1"
- syntax: "`T34.new(Suit.M, 5)`"
- params:
- - "`Suit`"
- - number
- returns:
- - "`T34`"
- desc: 通过花色与数值创建。
- -
- name: "构造2"
syntax: '`T34.new("5m")`'
params:
- string
returns:
- "`T34`"
- desc: 通过字符串创建。
+ desc:
+ 通过字符串创建。
+ 第一个字符代表数值,第二个字符代表花色。
+ `"1m"`, `"2p"`, `"3s"`代表 1 万、2 饼、3 索;
+ `"1f"`, `"2f"`, `"3f"`, `"4f"`, `"1y"`, `"2y"`, `"3y"`分别代表东南西北白发中。
-
- name: "构造3"
+ name: "构造2"
syntax: "`T34.new(4)`"
params:
- number
@@ -33,6 +28,34 @@
returns:
- number
desc: 获取 ID-34。
+ -
+ name: "`suit`"
+ syntax: "`t:suit()`"
+ params:
+ returns:
+ - string
+ desc:
+ 获取花色。
+ `"m"`, `"p"`, `"s"`, `"f"`, `"y"`分别表示万、饼、索、风牌、三元牌。
+ -
+ name: "`val`"
+ syntax: "`t:val()`"
+ params:
+ returns:
+ - number
+ desc:
+ 获取数值。
+ 数牌返回 1~9;
+ 风牌通过 1, 2, 3, 4 分别表示东南西北;
+ 三元牌通过 1, 2, 3 分别表示白发中。
+ -
+ name: "`str34`"
+ syntax: "`t:str34()`"
+ params:
+ returns:
+ - string
+ desc:
+ 获取对应的字符串。
-
name: "`isyakuhai`"
syntax: "`t:isyakuhai(sw, rw)`"
@@ -50,10 +73,53 @@
- "`T34`"
returns:
- boolean
- desc: "判断两张牌是否相等,无视赤黑。"
+ desc: "判断两张牌是否相等。同花色的赤 5 和黑 5 也是相等的。"
- name: "static `all`"
syntax: "`ipairs(T34.all)`"
desc: 遍历全部 34 种牌。
+-
+ name: T37
+ members:
+ -
+ name: "构造1"
+ syntax: '`T37.new("0m")`'
+ params:
+ - string
+ returns:
+ - "`T37`"
+ desc:
+ 通过字符串创建。
+ 可通过`"0m"`, `"0p"`, `"0s"`创建赤宝牌,其余同`T34`。
+ -
+ name: "构造2"
+ syntax: "`T37.new(4)`"
+ params:
+ - number
+ returns:
+ - "`T37`"
+ desc: 通过 ID-34 创建。此方法不创建赤牌。
+ -
+ name: 继承的方法
+ syntax: "`t.suit()`, `t.val()`, ..."
+ params:
+ returns:
+ desc: "`T34`的方法也可以用在`T37`上。"
+ -
+ name: "`isaka5`"
+ syntax: "`t:isaka5()`"
+ params:
+ returns:
+ - string
+ desc:
+ 判断是否为赤 5。
+ -
+ name: "`str37`"
+ syntax: "`t:str37()`"
+ params:
+ returns:
+ - string
+ desc:
+ 获取对应的字符串,以`"0m"`, `"0p"`, `"0s"`表示赤 5。
-
name: Who
members:
@@ -95,11 +161,10 @@
syntax: "`meld:type()`"
params:
returns:
- - "`M37.Type`"
+ - string
desc:
- 获取 meld 类型。
- 返回值为`M37.Type.CHII`, `M37.Type.PON`, `M37.Type.DAIMINKAN`,
- `M37.Type.ANKAN`, `M37.Type.KAKAN`中的一个。
+ 获取 meld 类型。返回值为
+ `"chii"`, `"pon"`, `"daiminkan"`,`"ankan"`, `"kakan"`中的一个。
-
name: "`[]`"
syntax: "`meld[2]`"
@@ -113,6 +178,50 @@
-
name: Mount
members:
+ -
+ name: "`remainpii`"
+ syntax: "`mount:remainpii()`"
+ params:
+ returns:
+ - number
+ desc: 查看壁牌残杖
+ -
+ name: "`remainrinshan`"
+ syntax: "`mount:remainrinshan()`"
+ params:
+ returns:
+ - number
+ desc: 查看岭上牌残杖
+ -
+ name: "`remaina`1"
+ syntax: "`mount:remaina(tile)`"
+ params:
+ - "`T34`"
+ returns:
+ - number
+ desc: 查看 A 区中`tile`的残杖
+ -
+ name: "`remaina`2"
+ syntax: "`mount:remaina(tile)`"
+ params:
+ - "`T37`"
+ returns:
+ - number
+ desc: 同上,以`T37`为参数,赤牌敏感
+ -
+ name: "`getdrids`"
+ syntax: "`mount:getdrids()`"
+ params:
+ returns:
+ - 某类似数组的`T37`容器
+ desc: 读取已翻出的(杠)宝牌指示牌序列
+ -
+ name: "`geturids`"
+ syntax: "`mount:geturids()`"
+ params:
+ returns:
+ - 某类似数组的`T37`容器
+ desc: 读取(立直和牌后)已亮出的(杠)里宝牌指示牌序列
-
name: "`lighta`1"
syntax: "`mount:lighta(tile, mk)`"
@@ -130,6 +239,50 @@
- boolean
returns:
desc: 同上,多一个指定是否为岭上出口的参数。
+ -
+ name: "`lightb`1"
+ syntax: "`mount:lightb(tile, mk)`"
+ params:
+ - "`T34`"
+ - number
+ returns:
+ desc: 以`mk`增加 B 区中`tile`的存在感。
+ -
+ name: "`lightb`2"
+ syntax: "`mount:lightb(tile, mk, rinshan)`"
+ params:
+ - "`T34`"
+ - number
+ - boolean
+ returns:
+ desc: 同上,多一个指定是否为岭上出口的参数。
+ -
+ name: "`incmk`1"
+ syntax: "`mount:incmk(exit, pos, tile, mk, bspace)`"
+ params:
+ - string
+ - number
+ - "`T34`"
+ - number
+ - boolean
+ returns:
+ desc:
+ 以`mk`增加出口`exit`之`pos`处`tile`的存在感。
+ `exit`需传入`"pii"`, `"rinshan"`, `"dorahyou"`, `"urahyou"`之一,
+ 分别代表普通壁牌、岭上牌、未翻开的表宝牌指示牌、未挖出的里宝牌指示牌。
+ `pos`为 0 时代表出口处队首牌,1 时代表队首的下一张牌,以此类推。
+ `bspace`为`true`时干涉 B 区,否则干涉 A 区。
+ -
+ name: "`incmk`2"
+ syntax: "`mount:incmk(exit, pos, tile, mk, bspace)`"
+ params:
+ - string
+ - number
+ - "`T37`"
+ - number
+ - boolean
+ returns:
+ desc: "`incmk`的赤牌敏感版,以`T37`为参数,其余同上"
-
name: Tilecount
members:
@@ -143,9 +296,9 @@
desc: 获取集合中`tile`的数量。
-
name: "`ct`2"
- syntax: "`tc:ct(Suit.M)`"
+ syntax: '`tc:ct("m")`'
params:
- - "`Suit`"
+ - string(详见`T34`的`suit`方法)
returns:
- number
desc: 获取集合中某一花色牌的数量。
@@ -174,6 +327,13 @@
returns:
- number
desc: 计算某种牌的数量,含副露。
+ -
+ name: "`ctaka5`"
+ syntax: "`hand:ctaka5()`"
+ params:
+ returns:
+ - number
+ desc: 计算赤 5 的数量,含副露。
-
name: "`ready`"
syntax: "`hand:ready()`"
@@ -230,6 +390,14 @@
returns:
- boolean
desc: 判断是否为门前清。
+ -
+ name: "`%`"
+ syntax: "`indicators % hand`, `tile % hand`"
+ params:
+ - "`mount:drids`或`mount:urids`的返回值,或`T34`"
+ returns:
+ - number
+ desc: 计算宝牌个数。
-
name: Game
members:
@@ -274,7 +442,14 @@
name: "`getroundwind`"
syntax: "`game:getroundwind()`"
params:
- - "`Who`"
returns:
- number
desc: 获取本局场风数值(1 ~ 4 分别表示东南西北)。
+ -
+ name: "`getriver`"
+ syntax: "`game:getriver(who)`"
+ params:
+ - "`Who`"
+ returns:
+ - "某类似数组的`T34`容器"
+ desc: 获取某家牌河。
diff --git a/_data/lua-callbacks.yml b/_data/lua-callbacks.yml
new file mode 100644
index 0000000..608d75a
--- /dev/null
+++ b/_data/lua-callbacks.yml
@@ -0,0 +1,53 @@
+-
+ name: checkinit
+ desc:
+ 检查配牌,当且仅当满意配牌时返回`true`
+ params:
+ -
+ name: game
+ type: userdata `Game`
+ desc: 当前牌桌数据
+ -
+ name: init
+ type: userdata `Hand`
+ desc: 待测配牌,无论亲子都是 13 张
+ -
+ name: who
+ type: userdata `Who`
+ desc: 待测配牌所有者
+ -
+ name: iter
+ type: number
+ desc: 检测轮数,从0 开始递增,最大 999
+-
+ name: ondraw
+ desc: 摸牌前被调用,可干涉牌山
+ params:
+ -
+ name: game
+ type: userdata `Game`
+ desc: 当前牌桌数据
+ -
+ name: mount
+ type: userdata `Mount`
+ desc: 牌山
+ -
+ name: who
+ type: userdata `Who`
+ desc: 将要摸牌的人
+ -
+ name: rinshan
+ type: boolean
+ desc: 下一张摸牌是否为岭上牌
+-
+ name: ongameevent
+ desc: 发生某些事件前调用,不可直接干涉牌山
+ params:
+ -
+ name: game
+ type: userdata `Game`
+ desc: 当前牌桌数据
+ -
+ name: event
+ type: table
+ desc: 发生的事件
diff --git a/bugging.md b/bugging.md
index f7fabf7..cc99a18 100644
--- a/bugging.md
+++ b/bugging.md
@@ -6,13 +6,11 @@ permalink: /bugging/
「骚扰」指反馈、众包任务过程中,
贡献者做出的极端烦人行为。
-本条例主要针对神经病设立,
-正常人不必过于担心骚扰判定问题。
+本条例默认不公开,只会针对性地出示给有必要警告的贡献者。
贡献者做出骚扰行为时,会被扣除一定的贡献度。
多数情况下,首次骚扰扣除 1000 点,往后则翻倍增加扣除额度。
-
下文详细定义了骚扰行为的判定标准。
1. 无知有理 - A 类
@@ -43,9 +41,9 @@ permalink: /bugging/
反馈者发布大量(刷屏级)无法获得贡献度的反馈时,
适用「垃圾反馈泛滥」判定。
若不具备自行鉴别垃圾反馈的能力,则应学会闭嘴。
-7. 催促验收
+7. 急太监
贡献者在众包平台上点击「通知验收」后,无需再通过其它途径另行通知验收。
- 通过其它途径通知验收、或询问验收时间,则「催促验收」判定成立。
+ 通过其它途径通知验收、或询问验收时间,则「急太监」判定成立。
8. 轻视审查
贡献者所提交的代码中反复犯同样的错误时,
「轻视审查」判定成立。
diff --git a/contribute.md b/contribute.md
index 5f38f17..d5a14cd 100644
--- a/contribute.md
+++ b/contribute.md
@@ -30,7 +30,8 @@ permalink: /contribute/
获得「贡献度」。
贡献度大于 0 的 ID 会出现在 app 封面上。
-同时,贡献度是零食的领取基准,每周领取零食量 = 50 x 贡献度。
+
+[注册松饼社区 ID](/signup/)
diff --git a/docs/abbr.md b/docs/abbr.md
new file mode 100644
index 0000000..3c5f6fc
--- /dev/null
+++ b/docs/abbr.md
@@ -0,0 +1,27 @@
+---
+layout: page
+title: 已认证常见缩写
+permalink: /docs/abbr/
+---
+
+下表中包括的都是可以在代码中随意使用的缩写。
+不包括的就不一定了,有可能能用也有可能不能用。
+
+建议使用「Ctrl + F」搜索。
+
+
+
+ 缩写 |
+ 全称 |
+ 解释 |
+
+{% assign sorted-abbr = site.data.abbr | sort: 'abbr' %}
+{% for abbr in sorted-abbr %}
+
+ {{ abbr.abbr }} |
+ {{ abbr.full }} |
+ {{ abbr.desc | markdownify }} |
+
+{% endfor %}
+
+
diff --git a/docs/cpp-note.md b/docs/cpp-note.md
index 196e100..3d0e9a0 100644
--- a/docs/cpp-note.md
+++ b/docs/cpp-note.md
@@ -8,9 +8,9 @@ permalink: /docs/cpp-note/
返回[松饼 C++ 代码规范](/docs/cpp/)页面
-## 对”简单阶梯形“与”简单锯齿形“的定义
+## 对「简单阶梯形」与「简单锯齿形」的定义
-“简单阶梯形”的基本定义:缩进层级逐行加一。
+「简单阶梯形」的基本定义:缩进层级逐行加一。
```
// 简单阶梯形
@@ -37,7 +37,7 @@ while (hungry()) {
- 条件必须只占一行。只要条件占据多行,就不是简单阶梯形。
- 带有`else`的`if`不属于简单阶梯形。
-“简单锯齿形”的基本定义:缩进层级逐行交替增减的`if`语句。
+「简单锯齿形」的基本定义:缩进层级逐行交替增减的`if`语句。
```
// 简单锯齿形
diff --git a/docs/cpp.md b/docs/cpp.md
index d2ed2a8..0075040 100644
--- a/docs/cpp.md
+++ b/docs/cpp.md
@@ -40,7 +40,7 @@ permalink: /docs/cpp/
- 要:`Http`(大驼峰),`http`(小驼峰)
- [NM-6] 用小写字母或数字为 namespace 命名。
- [NM-7] 用大写字母和下划线为枚举值和常量命名。
-- [NM-8] 鼓励使用短命名与常见的缩写。
+- [NM-8] 鼓励使用短命名与[常见的缩写](/docs/abbr/)。
- [NM-9] 命名需带有自解释性,禁止使用无意义命名。
- 好:`Dog odie;`
- 可以:`Dog d;`(`d`可看作`Dog`的缩写)
diff --git a/docs/dev-setup.md b/docs/dev-setup.md
index b81a9d0..ee89227 100644
--- a/docs/dev-setup.md
+++ b/docs/dev-setup.md
@@ -4,71 +4,97 @@ title: 搭建开发环境
permalink: /docs/dev-setup/
---
-## 概述
+## 索引
-所有的松饼项目都可以在 Linux, Windows, macOS 上开发。
+根据使用的平台和开发的目标选读:
-如果没啥特殊情况,强烈建议按照以下流程搭建环境。
-我们的开发环境对现有系统应该没有污染性。
-不按照以下步骤搭环境的,我们无法予以帮助。
+- [在 Linux 上开发`libsaki`或`mjpancake`](#linux-client)
+- [在 Windows 上开发`libsaki`或`mjpancake`](#windows-client)
+- [在 macOS 上开发`libsaki`或`mjpancake`](#macos-client)
+- [开发 Android 客户端](#android)
+- [开发`ih`](#ih)
-
+{% capture client-cond %}
+理论上,只要满足以下所有条件,就可以进行开发:
-## 客户端或核心库的环境搭建
+- 有一个完整支持 C++17 的编译器
+- 装有最新版 Qt
+{% endcapture %}
-1. 根据平台不同,安装一些必要的东西
- - Windows:安装 [mingw-w64][mingw-w64]{:target="_blank"}
- - 安装路径不能带空格
- - 安装时选择「最新版, i686, posix, dwarf」
- - macOS:通过 AppStore 安装最新版 Xcode
- - Linux:GCC/G++ 7.x 或以上
-2. 下载并安装 Qt 5.10.1 开源版
+{% capture install-qt %}
+1. 下载并安装 Qt 5.11.1 开源版
- 下载地址:[镜像][qt-mirror]{:target="_blank"}
或 [官网][qt]{:target="_blank"}
- - 大陆网络环境下推荐使用镜像
- - Windows 安装时勾选 MinGW 组件
- - Windows 安装 Qt 后需要额外的配置,见下面的 [关于Windows构建](#winbuild)
-3. 从`mjpancake`和`libsaki`创建fork (为将来方便,两个都fork)
- - 进入[`mjpancake`][mjpancake]{:target="_blank"}页面,点右上角的fork
- - 进入[`libsaki`][libsaki]{:target="_blank"}页面,点右上角的fork
-4. 通过以下命令克隆仓库并配置`upstream`远端:(替换掉`your-username`)
+ - 大陆网络环境下推荐使用镜像
+{% endcapture %}
+
+{% capture create-fork %}
+1. 从 [`mjpancake`][mjpancake]{:target="_blank"}
+ 以及 [`libsaki`][libsaki]{:target="_blank"} 创建 fork
+ - 同时可通过加 star 方便将来访问
+1. 通过以下命令克隆仓库并配置`upstream`远端:(替换掉`your-username`)
- `git clone --recursive https://github.com/your-username/mjpancake.git`
- `cd mjpancake`
- `git remote add upstream https://github.com/rolevax/mjpancake.git`
- `cd libsaki`
- `git remote rename origin upstream`
- `git remote add origin https://github.com/your-username/libsaki.git`
+ - 在以后的交流中,我们会假定`origin`指代 fork 出的仓库,
+ `upstream`指代松饼的官方仓库。
+{% endcapture %}
-在以后的交流中,我们会假定`origin`与`upstream`都是用上述命令配出来的。
-
+{% capture client-end %}
环境搭建好以后,
用 Qt Creator 打开代码目录下的`mjpancake.pro`项目,
-点击左下角的Build按钮进行编译。
+点击左下角的 Build 按钮进行编译。
编译成功通过则说明环境搭建完成。
+首次编译时可能会报出有关 QML 的语法错误,
+此系静态分析器的问题所致,不影响程序的运行时行为,可无视。
+
`libsaki`和`mjpancake`之间不存在必须同步更新的关系。
众包平台上的任务通常只需要修改`mjpancake`和`libsaki`中的一个,
不会出现两者都需要提交的情况。
首次接触`libsaki`代码的,
建议阅读[Libsaki代码导读](/docs/libsaki/),快速了解整体设计。
+{% endcapture %}
+
+## 在 Linux 上开发 libsaki 或 mjpancake
+
+{{ client-cond }}
+
+具体步骤:
-
+1. 安装 7.x 或以上的 G++{{ install-qt }}{{ create-fork }}{{ client-end }}
-## 关于 Windows 构建
-Qt 自带的 mingw 编不过 Libsaki,
-我们的解决方案是使用 mingw-w64。
-(mingw 和 mingw-w64 是两家东西)
+## 在 Windows 上开发 libsaki 或 mjpancake
-打开 Qt Creator,「工具」->「选项」,
-将 C 与 C++ 的编译器都改成 mingw-w64 的,如下图。
+{{ client-cond }}
+
+具体步骤:
+
+1. 安装 [mingw-w64][mingw-w64]{:target="_blank"}
+
+ - 安装路径不能带空格
+ - 安装时选择「最新版, i686, posix, dwarf」
+{{ install-qt }} - 安装时勾选 MinGW 组件
+{{ create-fork }}
+1. 打开 Qt Creator,「工具」->「选项」,
+ 将 C 与 C++ 的编译器都改成 mingw-w64 的,如下图。

-
+{{ client-end }}
+
+## 在 macOS 上开发 libsaki 或 mjpancake
-## 关于 Android 客户端
+1. 通过 AppStore 安装最新版 Xcode{{ install-qt }}
+{{ create-fork }}
+{{ client-end }}
+
+## 开发 Android 客户端
Qt 官方建议使用 Android NDK r10e,
然而 r10e 自带的 G++ 编不过 Libsaki。
@@ -80,9 +106,7 @@ Qt 官方建议使用 Android NDK r10e,
3. 通过 NDK 里的 Clang 编译 Qt(需要几个小时)
4. 通过这个新编译出的 Qt 构建`mjpancake.pro`
-
-
-## 服务器开发环境搭建
+## 开发 ih
`ih`的开发环境和运行环境都被做成了 Docker 镜像,
因此需要安装的东西只有 Docker 和 Docker Compose。
@@ -108,7 +132,7 @@ Qt 官方建议使用 Android NDK r10e,
[mingw-w64]: https://mingw-w64.org/doku.php/download/mingw-builds
[git-win]: https://git-for-windows.github.io/
[qt]: https://www.qt.io
-[qt-mirror]: http://mirrors.ustc.edu.cn/qtproject/archive/qt/5.10/5.10.1/
+[qt-mirror]: http://mirrors.ustc.edu.cn/qtproject/archive/qt/5.11/5.11.1/
[docker]: https://docs.docker.com/engine/installation/
[docker-compose]: https://docs.docker.com/compose/install/
diff --git a/docs/editor/api.md b/docs/editor/api.md
index a514479..b32cb93 100644
--- a/docs/editor/api.md
+++ b/docs/editor/api.md
@@ -7,7 +7,15 @@ permalink: /docs/editor/api/
本页包含松饼人物编辑器目前为止的全部接口。
推荐使用「Ctrl + F」进行查找。
-## 回调函数
+## 索引
+
+- [回调函数](#callback)
+- [可用的 Lua 标准库与内建函数](#std)
+- [各 userdata 接口](#userdata)
+- [Game Event 表结构](#event)
+- [与 C++ 接口的关系](#cpp)
+
+## 回调函数
在顶级 chunck 中以特定的名字定义函数,
即可在对应时刻执行指定的逻辑。
@@ -15,36 +23,44 @@ permalink: /docs/editor/api/
这些函数都不需要参数,
必要的数据可从特定的全局变量中获取。
-|-------|--------|--------|
-|函数名|调用时机|可用全局变量|
-|-------|--------|--------|
-|`ondraw`|摸牌之前|`game`, `mount`, `who`, `rinshan` |
-|-------|--------|--------|
-
-## 全局变量
-
-为了免除在写回调时记忆参数顺序的麻烦,
-我们使用名字固定的全局变量提供必要的数据。
-可以把这些全局变量的名字当成关键字看待。
-
-在一个回调函数的内部,
-并非所有的全局变量都是可用的。
-上面的「回调函数」表中列举了在哪些回调中可使用哪些全局变量。
-
-|-------|--------|--------|
-|变量名 |类型|简介|
-|--------|--------|--------|
-|`game`|userdata `Game`|当前牌桌数据|
-|`mount`|userdata `Mount`|牌山|
-|`who`|userdata `Who`|事件关系人|
-|`rinshan`|boolean|下一张摸牌是否为岭上牌|
-|`self`|userdata `Who`|本角色,在所有回调中可用|
-|--------|--------|--------|
+
+
+ 函数名 |
+ 作用 |
+
+{% for cb in site.data.lua-callbacks %}
+
+ {{ cb.name }} |
+ {{ cb.desc | markdownify | remove: " " | remove: " " }} |
+
+
+
+ 可用全局变量:
+
+{% for param in cb.params %}
+ {{ param.name }}
+
+ - 类型:{{ param.type | markdownify | remove: "
" | remove: " " }}
+ - {{ param.desc | markdownify | remove: "
" | remove: " " }}
+
+
+{% endfor %}
+ self
+
+ - 类型:userdata
Who
+ - 本角色
+
+
+
+ |
+
+{% endfor %}
+
-## 可用的 Lua 标准库与内建函数
+## 可用的 Lua 标准库与内建函数
-为了防止世界被破坏,为了维护世界的和平,
-松饼中能用的 Lua 标准库与内建函数是原版 Lua 的一个子集。
+为了防止世界被破坏,
+松饼中只能使用一部分的 Lua 标准库与内建函数。
能用的部分:
@@ -53,10 +69,11 @@ permalink: /docs/editor/api/
- `math`中除去`math.random`和`math.randomseed`以外的所有函数
- `pairs`, `ipairs`
- `print`
+- `tostring`
将来可能会放宽限制,支持更多的标准库成员。
-## 各 userdata 接口
+## 各 userdata 接口
{% for class in site.data.lua-api %}
{{ class.name }}
@@ -67,8 +84,8 @@ permalink: /docs/editor/api/
{% for member in class.members %}
- {{ member.name | markdownify }} |
- {{ member.syntax | markdownify }} |
+ {{ member.name | markdownify|remove:" "|remove:" " }} |
+ {{ member.syntax | markdownify|remove:" "|remove:" " }} |
参数类型 |
@@ -76,7 +93,7 @@ permalink: /docs/editor/api/
{% assign ps = member.params[0] %}
{% assign tail = member.params | shift %}
{% for p in tail %}{% assign ps = ps | append: ", " | append: p %}{% endfor %}
- {{ ps | markdownify }}
+ {{ ps | markdownify | remove: "" | remove: "
" }}
@@ -85,13 +102,34 @@ permalink: /docs/editor/api/
{% assign rs = member.returns[0] %}
{% assign tail = member.returns | shift %}
{% for r in tail %}{% assign rs = rs | append: ", " | append: r %}{% endfor %}
- {{ rs | markdownify }}
+ {{ rs | markdownify | remove: "" | remove: "
" }}
- {{ member.desc | markdownify }} |
+
+ {{ member.desc | markdownify | remove: " " | remove: " " }}
+ |
{% endfor %}
{% endfor %}
+## Game Event 表结构
+
+`ongameevent`中使用的`event`变量类型为 table,
+包含`type`和`args`两个字段。
+`type`字段为 string 类型,表示事件的类别;
+`args`字段为 table 类型,根据`type`的不同含有不同的字段。
+
+(文档准备中。目前可通过自行`pairs`遍历查看`args`内容。)
+
+## 与 C++ 接口的关系
+
+松饼的 Lua 接口与 C++ 接口之间存在以下关联与区别:
+
+- C++ 里的`Table`在 Lua 中一律改称`Game`
+- C++ 接口基于驼峰命名,Lua 的命名方式参照标准库,全小写且无分隔
+ (userdata 类名首字母大写)
+- C++ 以 assert 或 UB 处理傻逼逻辑,Lua 则会报运行时错误
+ (Lua 代码导致松饼主程序崩溃的情况属于 bug)
+
diff --git a/docs/editor/flow.md b/docs/editor/flow.md
new file mode 100644
index 0000000..45c1a15
--- /dev/null
+++ b/docs/editor/flow.md
@@ -0,0 +1,190 @@
+---
+layout: page
+title: 控制流
+permalink: /docs/editor/flow/
+---
+
+「松饼人物编辑器:从入门到欧耶」系列教程(六)
+
+## 上一讲的习题参考答案
+
+
+
+## 多级 if 嵌套
+
+回顾一下第一讲中,自己摸牌输出「哇!」,
+别人摸牌输出「emmm...」的那个例子:
+
+```lua
+function ondraw()
+ if who == self then
+ print("哇!")
+ else
+ print("emmm...")
+ end
+end
+```
+
+现在我们把这个例子扩展一下,
+让它在下家摸牌的输出「鄙视下家」,其余的不变:
+
+```lua
+function ondraw()
+ if who == self then
+ print("哇!")
+ else
+ if who == self:right() then
+ print("鄙视下定")
+ else
+ print("emmm...")
+ end
+ end
+end
+```
+这段代码的意思是:
+
+- 如果摸牌的人是自己:
+ - 输出「哇!」
+- 否则:
+ - 如果摸牌的人是自己的下家:
+ - 输出「鄙视下家」
+ - 否则:
+ - 输出「emmm...」
+
+就像上面的例子所展示的一样,`if`里面可以嵌套`if`。
+我们不妨再套一层,让它在对家摸牌时输出「嫌弃对家x」。
+
+```lua
+function ondraw()
+ if who == self then
+ print("哇!")
+ else
+ if who == self:right() then
+ print("鄙视下定")
+ else
+ if who == self:cross() then
+ print("嫌弃对家x")
+ else
+ print("emmm...")
+ end
+ end
+ end
+end
+```
+
+道理很简单,就是一级一级地判断 ——
+但是这画风太鬼畜了,看着就晕,尤其是最后的`end`四连,简直洗脑x
+
+好在 Lua 提供了一种方便的写法 —— `elseif`:
+
+```lua
+function ondraw()
+ if who == self then
+ print("哇!")
+ elseif who == self:right() then
+ print("鄙视下定")
+ elseif who == self:cross() then
+ print("嫌弃对家x")
+ else
+ print("emmm...")
+ end
+end
+```
+
+通过`elseif`,代码的逻辑没有变,但看起来舒服了很多,也避免了鬼畜的`end`四连。
+
+虽然我们已经用过很过次`ondraw`函数和`if`语句了,
+但里面的很多东西其实都没讲清楚,下面详细补充一下。
+
+
+
+## 解释器的工作方式
+
+先解释一下松饼 Lua 解释器的工作方式。
+
+每一个角色都运行在独立的环境里,
+它们之间无法直接通过共享全局变量来串通。
+
+在一桌开始时,系统会把在场人物的 Lua 文件都运行一遍,
+这个过程我们姑且称为「初始化」。
+在初始化期间,代码可以定义一些全局函数,准备一些全局变量。
+这个时候也可以定义局部变量,搞一些计算 ——
+初始化结束后,全局变量会被保留。
+
+想要实现摸牌挂,就要定义`ondraw`全局变量,其类型为函数。
+过后,每当有人摸牌时,解释器都会在摸牌之前先调用`ondraw`。
+
+`ondraw`的定义内部可使用`who`,`self`等全局变量。
+这些变量是由系统从外部直接塞进来的,拿来用就行了。
+
+
+
+## if 的工作方式
+
+最简单的`if`语句长这个样子:
+
+```lua
+if 条件 then
+ 语句1
+ 语句2
+ 语句3
+ ...
+end
+```
+
+「条件」的求值结果为「真」,则执行里面的那堆语句(称做「语句体」),
+「条件」为「假」时则会跳过语句体,执行`end`后面的代码。
+
+if 语句可以有 else 部分和/或 elseif 部分:
+
+```lua
+if 条件1 then
+ 语句体1
+elseif 条件2 then
+ 语句体2
+elseif 条件3 then
+ 语句体3
+else
+ 语句体N
+end
+```
+
+这种情况下,会先计算「条件1」。
+「条件1」为「真」,则执行「语句体1」。
+「条件1」为「假」,则继续计算「条件2」,以此类推。
+这里需要注意的是计算的顺序。如果前面的条件为「真」,
+后面的条件就不会被计算。
+
+每一个语句体都会开启一个新的局部变量的作用域(即「块」)。
+
+在 Lua 中,boolean 类型的`false`,和 nil 类型的`nil`是「假」,
+其余的任何类型的任何值都是「真」。
+这意味着 number 类型的`0`,string 类型的`""`也都是「真」。
+
+
+
+## for 循环
+
+
+
+## while 和 repeat 循环
+
+
+
+## 逻辑运算
+
+
+
+## 练习题
+
+1) 判断以下表达式真假:
+```lua
+nil == "nil" or nil
+nil == ("nil" and nil)
+1 + 1 == 2 or nil
+1 + 1 ~= (2 or nil)
+(0 and true) and T34.new("3y") or false
+```
+
+下一讲:[表](/docs/editor/table/)
+
diff --git a/docs/editor/func.md b/docs/editor/func.md
index 6206e12..f43ef01 100644
--- a/docs/editor/func.md
+++ b/docs/editor/func.md
@@ -9,18 +9,35 @@ permalink: /docs/editor/func/
## 上一讲的习题参考答案
1) `a`, `b`, `c`满天飞,滥用隐式类型转换(等等)
-2) 合法:`doge`, 非法:`good-doge`
+2) 合法:`doge`, 非法:`good-doge`(因为有中划线)
3) number, string, nil, boolean
4) `false`
-## 函数
-
-函数是确保代码可维护性的重要手段之一。
+## 可维护性了解一下
所谓「可维护」,就是指改起来方便。
-代码改起来方不方便,可以决定项目的生死。
+改起来方便的代码会越改越好,
+而改起来不方便的代码则吃枣药丸。
+
+很多学生党写代码都不怎么重视可维护性。
+这是因为他们写的东西,无论是作业、课题还是竞赛中提交的答案,
+都是「一次性」的代码 —— 今天完成任务以后,明天就再也不用改了。
+对于一次性代码来讲,可维护性自然并不重要;
+但如果想写一个真正「有用」的东西,就不能这么玩了 ——
+因为这些东西将来是要反复修改的 —— 加功能、调细节、改 bug。
+若不重视可维护性,
+每当想新增一些功能、调整一些细节、修复一些 bug 的时候,
+都会分分钟突然失去梦想x
+
+所以可维护性大法好。
+
+
+
+## 函数
+
+通过函数,可以简单粗暴地提高代码的可维护性。
举一个粟子:
@@ -89,8 +106,10 @@ poetize("姬子")
```
三狗测试,见以上代码又吹我爽,又吹军师,又吹龙华,又吹姬子。
+每吹一人,都只需简单加上一行代码。
+只要愿意,甚至可以随时来上一句`poetize("京狗")`,十分方便。
如果不用函数,这么一波吹下来,得写上大量的重复代码,
-不旦写着麻烦,将来改起来也麻烦。
+不旦写着麻烦,看着不爽,将来改起来也麻烦。
所以,函数大法好。
多用函数,简化代码,延年益寿,岂不美哉x
@@ -112,8 +131,7 @@ poetize("军师")
这段代码定义了一个叫`poetize`的函数,
然后以`"军师"`为参数调用了一下它。
-- 定义函数时,先写`function`,再写函数名,
- 再写「参数列表」,再写定义的内容,最后写`end`。
+- 定义函数时,需要在函数名后面加一个「参数列表」。
所谓「参数列表」,就是一个括号,里面写上任意个变量名。
本例中我们只写了一个`name`变量。
- 调用函数时,先写函数名,再加个括号,
@@ -133,12 +151,61 @@ poetize("军师", "x")
poetize("军师", "!")
```
+函数也可以没有参数。
+定义和调用没有参数的函数的时候,在函数名后面加一对空的括号:
+
+```lua
+function poetize()
+ print("我爽美如画")
+end
+
+poetize()
+```
+
## 返回值
-函数是可以「返回」值的。
+函数可以有一个计算结果,比如:
+
+```lua
+function plus1(x)
+ return x + 1;
+end
+
+print(plus1(2))
+```
+
+结果输出 3。
+这里我们用到了`return` ——
+`return`就是给出这个函数的计算结果。
+
+不过之前「我爽」的那个函数里没有`return`。
+在 Lua 中,函数可以有`return`,也可以没有`return`。
+没有`return`函数计算结果为`nil`:
+
+```lua
+function f(x)
+end
+
+a = f(2)
+print(a)
+```
+
+结果输出 `nil`。另外`return`后面不加表达式时,计算结果也是`nil`:
+
+```lua
+function f(x)
+ return
+end
+
+a = f(2)
+print(a)
+```
+
+`return`意为「返回」,函数的计算结果也叫「返回值」。
「返回」的意思是说,哪儿来的回哪儿去。
+举个栗子:
```lua
function f(x)
@@ -156,15 +223,156 @@ print(g("我爽"))
三狗测试,见输出「我爽我爽美如画!」。
这个「我爽我爽美如画!」是怎么算出来的呢?
-首先,这个输出肯定是从`print`那里出来的,
-也就是说,那个`g("我爽")`的值就是`"我爽我爽美如画!"`。
-那么`g("我爽")`的值又为什么是`"我爽我爽美如画!"`?
+这段代码干了三件事:
+
+1. 定义`f`函数
+2. 定义`g`函数
+3. 调用`print`函数
+
+其中,定义函数是不会产生输出的,
+产生输出的是最后的`print`那一行代码:
+```
+print(g("我爽"))
+```
+
+在 Lua 中,调用一个函数之前,会先把参数的值求出来。
+所以在执行到`print(g("我爽"))`时,
+会先去求`g("我爽")`的值,再用求出来的结果去继续调用`print`。
+
+于是这段代码接下来就会跳到`g`的定义,开始求`g("我爽")`的值。
+`g`的定义一共有两行,其中第一行为:
+```lua
+y = f(x) .. "美如画"
+```
+由于我们传入的`x`是`"我爽"`,这一行此时相当于是:
+```lua
+y = f("我爽") .. "美如画"
+```
+也就是将`f("我爽")`和`"美如画"`拼接成一个新的字符串,赋值给`y`。
+为了得到这个拼接的结果,
+Lua 接下来会先去求`f("我爽")`的值。
+于是我们跳到的`f`的定义。`f`的定义里只有一行:
+```lua
+return x .. x
+```
+由于我们传入的`x`是`"我爽"`,这一行相当于:
+```lua
+return "我爽" .. "我爽"
+```
+也就是:
+```lua
+return "我爽我爽"
+```
+`return`后面的表达式的求值结果,就是这个函数的求值结果。
+接下来就是把这个结果「返回」的时候了。
+返回结谁?从哪儿来的,就返回给谁。
+刚才是从这一行来的:
+```lua
+y = f("我爽") .. "美如画"
+```
+现在`f("我爽")`的值求完了,这一行也就成了:
+```lua
+y = "我爽我爽" .. "美如画"
+```
+也就是:
+```lua
+y = "我爽我爽美如画"
+```
+接下来,继续执行`g`的后面一行:
+```lua
+return y .. "!"
+```
+这行现在相当于:
+```lua
+return "我爽我爽美如画" .. "!"
+```
+也就是:
+```lua
+return "我爽我爽美如画!"
+```
+接着,再把这个结果返回给当初调用`g`的地方,也就是`print`那一行:
+```
+print(g("我爽"))
+```
+现在相当于:
+```
+print("我爽我爽美如画!")
+```
+于是这段代码最终输出了「我爽我爽美如画!」。
+
+
+
+## 提前返回
+
+`return`语句通常写在函数结尾,但也可以提前出现。
+`return`出现在函数中途时,函数后面的部分都会被跳过,
+直接返回到调用函数的地方。
+
+提前返回常用于错误处理:见事不好,调头就跑。
+
+```lua
+function f(name)
+ if name == "京狗" then
+ print("帅哥你谁啊")
+ return
+ end
+
+ print(name .. "美如画")
+end
+
+f("我爽")
+f("京狗")
+```
-这得看`g`这个函数是怎么定义的。
+测试知先后输出「我爽美如画」和「帅哥你谁啊」。
+当输入参数为京狗时,美如画的部分并没有被执行。
-(TODO)
+提前返回有助于提早排除有毒的输入参数,
+减少缩进层级,使后面的代码写起来更爽。
-## 局部变量
+## 练习题
+
+1) 预测以下代码输出:
+```lua
+function f(x)
+ return x + 1
+end
+
+function g(x)
+ return 2 * f(x)
+end
+
+a = f(1) + g(2)
+print(a)
+```
+
+2) 预测以下代码输出:
+```lua
+function f()
+ print("f1")
+ return "f2"
+end
+
+function g()
+ print("g1")
+ print(f())
+ print("g2")
+end
+
+g()
+```
+
+3) 完成`repeat3`的定义,使代码输出「嗷嗷嗷」。
+
+```lua
+function repeat3(str)
+ -- TODO 在此处填写实现
+end
+
+print(repeat3("嗷"))
+```
+
+下一讲:[局部变量](/docs/editor/local/)
diff --git a/docs/editor/local.md b/docs/editor/local.md
new file mode 100644
index 0000000..0897537
--- /dev/null
+++ b/docs/editor/local.md
@@ -0,0 +1,335 @@
+---
+layout: page
+title: 局部变量
+permalink: /docs/editor/local/
+---
+
+「松饼人物编辑器:从入门到欧耶」系列教程(四)
+
+## 上一讲的习题参考答案
+
+1) 抄代码运行即可验证
+2) 抄代码运行即可验证
+3) 一个参考:
+```lua
+function repeat3(str)
+ return str .. str .. str
+end
+
+print(repeat3("嗷"))
+```
+
+
+## 脑容量问题
+
+写代码时,我们会不断地「起名字」
+—— 有时给变量起名,有时又给函数起名。
+起的名字越多,记忆的负担也就越大 ——
+我们需要记住,这个函数是干什么的,那个变量又是干什么的。
+有时候,可能会由于疏忽,把某个已经有了某个用途名字,
+当成一个新名字用到另一个用途上 ——
+两块功能交替使用一个名字,结果出了一堆奇怪的错误。
+
+举个粟子:
+
+```lua
+function repeat2(x)
+ a = x .. x
+ return a
+end
+
+a = "哇"
+b = repeat2("哈")
+print(a .. b)
+```
+
+首先,定义一个把字符串重复 2 次的函数`repeat2`。
+然后,`a`是「哇」,`b`是重复两次的「哈」,打印`a .. b`。
+结果会输出什么?
+
+> 肯定是「哇哈哈」啊,这种局面还看不懂吗?
+
+(测试见输出「哈哈哈哈」)
+
+> …枼?…别啊?!哎~!呀~!这解说不下去了,哎呀这!!呃啊~~
+
+(为什么会变成这样呢……)
+
+要想修正这个问题,要么`repeat2`里别用`a`,要么外面别用`a`。
+总之就是只能有一个地方能用`a`。
+不管代码写得多长,都得记住`a`是给哪一段代码用的 ——
+除了那段代码,其它地方都不能用`a`。
+
+这就坑爹了。你得记住每一个变量名都是用在哪里的,不论代码有多长。
+这是想把人脑袋撑爆啊x
+
+所以,局部变量大法好。
+
+
+
+## 关键字 local
+
+用`local`大法,将刚才的代码改写如下:
+
+```lua
+function repeat2(x)
+ local a = x .. x
+ return a
+end
+
+a = "哇"
+b = repeat2("哈")
+print(a .. b)
+```
+
+测试见输出「哇哈哈」。
+
+对一个变量赋值前,前面加上`local`,
+表明被赋值的变量是一个新创建的「局部变量」。
+
+局部变量,就是只在局部有效的变量。
+比如你在麻吧里说「老板」,指的肯定就是照老板,
+不是其它的什么老板。
+这个时候,「麻吧」就是一个「局部」,在这个局部里,「老板」特指这个局部里的照老板。
+
+在`repeat2`函数中,由于`a`被声明成了一个局部变量,
+在`repeat2`内的`a`指的都是`repeat2`里的这个`a`,
+跟外面`a = "哇"`的那个`a`就完全没关系了。
+
+
+
+## 作用域
+
+局部变量从对应的`local`那一行开始可以用,
+到声明了这个`local`所在的「块」的结束就不能再用了。
+所谓的「块」,可以是函数,也可以是`if`语句,也可以是以后介绍的其它东西。
+习惯上,每进入一个新的「块」,都会增加一级缩进。
+
+在一个「块」里使用一个名字时,
+如果这个「块」里有叫这个名字的局部变量,
+那么这个名字指的就是这个局部变量。
+如果这个「块」里没有叫这个名的局部变量,
+这个名字指的就是外面的「块」里的局部变量。
+外面的「块」还没有,就到外面的外面的「块」里去找。
+如果连最外面的「块」里也没有,这个名字指的就是全局变量。
+
+举个粟子:
+
+```lua
+function f()
+ print(a) -- A
+ local a = 1
+ print(a) -- B
+ if true then
+ print(a) -- C
+ local a = 2
+ print(a) -- D
+ end
+ print(a) -- E
+end
+
+f()
+```
+
+以上代码先后输出 nil, 1, 1, 2, 1。
+
+从`--`到行尾的文字叫做「注释」,会被机器无视掉,是写给人看的。
+这里我们注释标出了 A, B, C, D, E 五个行,以便于说明。
+
+执行到 A 行的时候,当前代码所在的「块」就是函数`f`。
+这个「块」里还没有局部变量`a`,所以这个`a`指的是外面的`a`。
+外面也没有`a`,所以这里的`a`是个全局变量。
+我们没有碰过全局变量`a`,所以此行输出 nil。
+
+执行到 B 行的时候,当前的「块」里已经有局部变量`a`了,值为 1,所以输出1。
+
+执行到 C 行的时候,`if`语句开启了一个新的「块」。
+当前「块」里没有`a`,所以这里的`a`指的是外面的「块」里的`a`,
+也就是 1。
+
+执行到 D 行的时候,`if`「块」里也有了`a`,值为 2。
+所以此时的`a`指的就是这个`if`里新建的`a`。
+
+到了 E 行,已经退出了`if`「块」,所以`if`里的那个`a`已经没了。
+现在的`a`指的是函数「块」里的`a`,也就是 1。
+
+
+
+## 疯狂使用局部变量
+
+局部变量不但可以节约人的脑容量,
+还可以提高代码的运行速度(原理不展开)。
+所以`local`关键字应该能加就加。
+
+另外很多人都提倡尽可能在靠「内」的块里声明变量。
+举个粟子:
+
+```lua
+function f()
+ local a = 1
+ if true then
+ print(a)
+ end
+end
+```
+```lua
+function f()
+ if true then
+ local a = 1
+ print(a)
+ end
+end
+```
+
+上面的两段代码所做的事情是相同的,但第二段代码读起来更舒服。
+第一段代码中,`if`外面明明没有用到`a`,却把`a`放到了`if`外面,愣是增加了理解的难度。
+
+
+
+## 函数的参数
+
+函数的参数虽然不带`local`字样,但都是局部变量,只在函数内有效。
+
+调用函数的时候,传的是「值」
+—— 值会被复制一份,对复制品的操作影响不到原品。
+
+```lua
+function f(x)
+ x = 2
+end
+
+a = 1
+f(a)
+print(a)
+```
+
+上面的代码输出 1,而不是 2。在调用`f(a)`的时候,`a`的「值」
+—— 也就是 1 —— 被复制了一份给局部变量`x`。
+随后`x`这个局部变量被改成了 2,但这跟`a`有什么关系?所以最终输出 1。
+
+```lua
+function f(a)
+ a = 2
+end
+
+a = 1
+f(a)
+print(a)
+```
+
+上面的代码仍然输出 1。参数的名字被改成了`a`,
+但它也是一个仅在函数内存在的局部变量,跟外面的那个`a`没关系。
+
+
+
+## 上值与闭包
+
+和其它的变量一样,函数也是可以在局部随时创建的:
+
+```lua
+function f()
+ local function g()
+ print("a")
+ end
+
+ g()
+end
+
+f()
+```
+
+在函数的定义内,可以访问外部的局部变量。
+函数内使用到的外部的局部变量,叫「上值」。
+
+```lua
+function f()
+ local str = "a"
+ local function g()
+ print(str) -- str是g的一个上值
+ end
+
+ g()
+end
+
+f()
+```
+
+我们可以在函数里定义新函数并返回出去,达到用函数去创建函数的目的:
+
+```lua
+function make()
+ local str = "a"
+ local function g()
+ print(str)
+ end
+
+ return g -- 返回一个函数g
+end
+
+local h = make() -- 通过make函数创建h函数
+h() -- 调用h函数
+```
+
+每执行一次`function`与`end`之间的部分,
+都会产生一个新的函数。举个粟子:
+
+```lua
+function make()
+ local i = 1
+ local function g(x)
+ print(i)
+ i = x
+ end
+
+ return g
+end
+
+local h1 = make()
+local h2 = make()
+
+h1(233)
+h2(666)
+
+h1(0)
+h2(0)
+```
+
+测试见依次输出 1, 1, 233, 666。
+这可以证明`h1`和`h2`里面的上值`i`虽然名字相同,
+但并不是同一个变量。
+这是因为,`h1`与`h2`是在两次`make`的调用中创建的 ——
+每次调用`make`,都会创建一个新的局部变量`i`。
+随后,又创建新的函数`g`,这个新的函数引用了刚刚新建的`i`。
+所以`h1`与`h2`中的`i`指的就是两个不同的变量。
+
+可见,一个函数不仅代表一堆指令,还可以拥有只属于自己的一堆上值,
+就好像带着一个小包包一样。
+像这种带着包的函数,通常叫「闭包」。
+上面的例子中,函数`h1`和`h2`的定义虽然相同,但它们是两个不同的闭包。
+
+松饼的官方范例与之后的教程中,闭包并不常用;
+对于人物编辑而言,闭包也不是刚需。
+但为了避免写出 bug,或产生奇怪的误解,
+上值与闭包的基本概念还是必须要掌握的。
+
+
+
+## 练习题
+
+1) 判断题:「局部变量是给笨蛋用的,记忆力好的人不需要用局部变量。」
+2) 有些人喜欢把所有的局部变量声明写在函数开头,觉得这样很「清晰」,
+ 对此你怎么看?
+3) 完成`make`函数的定义,使代码先后输出「嗷」、「嗷嗷」、「嗷嗷嗷」。
+```lua
+function make(unit)
+ -- TODO 填写实现
+end
+
+ao = make("嗷")
+ao()
+ao()
+ao()
+```
+
+下一讲:[userdata](/docs/editor/userdata/)
+
diff --git a/docs/editor/start.md b/docs/editor/start.md
index 779a304..8bbb160 100644
--- a/docs/editor/start.md
+++ b/docs/editor/start.md
@@ -135,23 +135,23 @@ print("Vanishmennt this world!")
```lua
function ondraw()
- print("waaah!!")
+ print("哇!")
end
```
-三狗战测试,发现每当有人摸牌时都会输出一次「waaah!!」。
+三狗战测试,发现每当有人摸牌时都会输出一次「哇!!」。
这意味着,我们成功地实现了一个完整的摸牌挂 ——
每次摸牌时,这个挂都会生效 —— 虽然只是打印一行字。
不过多数情况下,自己的进张和他家的进张需要区别对待 ——
比如给自己塞有效牌,给他家塞铳牌什么的。
所以我们继续改进代码,让程序区另对待自己和他家的摸牌 ——
-自己摸牌时输出「waaaah!!」,而他家摸牌时输出「emmmm...」。
+自己摸牌时输出「哇!」,而他家摸牌时输出「emmmm...」。
```lua
function ondraw()
if who == self then
- print("waaah!!")
+ print("哇!")
else
print("emmm...")
end
@@ -171,7 +171,7 @@ end
```lua
function ondraw()
- print("waaah!!")
+ print("哇!")
end
```
@@ -192,7 +192,7 @@ end
```lua
function ondraw()
if who == self then
- print("waaah!!")
+ print("哇!")
else
print("emmm...")
end
@@ -229,7 +229,7 @@ end
```lua
function ondraw()
if who == self then
-print("waaah!!")
+print("哇!")
else
print("emmm...")
end
diff --git a/docs/editor/userdata.md b/docs/editor/userdata.md
new file mode 100644
index 0000000..d2c55af
--- /dev/null
+++ b/docs/editor/userdata.md
@@ -0,0 +1,208 @@
+---
+layout: page
+title: userdata
+permalink: /docs/editor/userdata/
+---
+
+「松饼人物编辑器:从入门到欧耶」系列教程(五)
+
+## 上一讲的习题参考答案
+
+1) 狗带(你慢慢记忆力良好x)
+2) 不符合多数人的习惯,所谓「清晰」也是主观的
+3) 一种可能的实现:
+
+```lua
+function make(unit)
+ local sum = unit
+ return function()
+ print(sum)
+ sum = sum .. unit
+ end
+end
+
+ao = make("嗷")
+ao()
+ao()
+ao()
+```
+
+
+## 使用松饼 userdata
+
+自从第二讲以来,好久没做人物技能了,一直都在写诗什么的x
+
+为了尽快切入我们的核心主题 —— 人物技能,
+这里我们要掌握基本的松饼 userdata 的用法。
+
+先回忆一下 Lua 中的七种数据类型:
+
+- number
+- string
+- boolean
+- table
+- function
+- userdata
+- nil
+
+其中我们没有直接用过的就剩 table 和 userdata 了。
+table 的用法以后再说,这里先看 userdata。
+
+userdata 与其它的类型有一点区别。
+其它的类型,都是 Lua 语言自带的,
+而 userdata 则是由应用(大环境)添加的。
+在松饼大环境下,userdata 就是麻将牌、牌山、牌桌这些东西。
+尽管同样是 Lua 语言,由于应用不同,使用 userdata 的方式也略有差异。
+为方便说明,下文中的 userdata 将特指松饼中的 userdata。
+
+
+
+## 麻将牌 T34
+
+松饼中有两种代表麻将牌的类型:`T34`与`T37`。
+区别在于后者将赤宝牌与普通的数牌 5 视为不同的类型。
+这里我们先看更常用的`T34`。
+
+写下`local i = 1`,就创建了一个 number 变量`i`;
+写下`local s = "xxx"`,就创建了一个 string 类型的`s`;
+写下`local b = true`,就创建了一个 boolean 类型的变量`b`。
+类似地,我们可以通过如下写法,创建一个「麻将牌」类型的变量`t`:
+
+```lua
+local t = T34.new("1s")
+```
+
+你会发现,创建麻将牌的写法,
+比创建 number, string, boolean 的写法要麻烦得多。
+这是理所当然的,毕竟麻将牌不是 Lua 的亲儿子,
+而是由松饼加进去的 userdata 类型。
+
+松饼对 userdata 类型进行了细化,
+将其分为`T34`, `Mount`, `Who`, `Game`等具体的类型,
+每个类型都有不同的用处,比如`T34`代表麻将牌,`Mount`代表牌山等等。
+我们先了解一下`T34`的用法。
+
+上面的例子中,`t`是一个`T34`类型的变量,其值为「一索」。
+`T34.new`其实就是一个函数,
+通过一个 string 类型的参数(上面的例子中的`"1s"`)指定想要创建的牌。
+这个 string 应该由两个字符组成,
+第一个字符代表牌的数值,第二个字符代表牌的花色,
+比如`"1s"`, `"7p"`, `"5m"`等等。
+在松饼中,万子、饼子、索子、风牌、三元牌分别用
+`m`, `p`, `s`, `f`, `y` 表示。
+风牌的数值为东1、南2、西3、北4;三元牌的数值为白1、发2、中3。
+比如,下面的代码创建了代表二饼和白板的变量`t1`与`t2`:
+
+```lua
+local t1 = T34.new("2p")
+local t2 = T34.new("1y")
+```
+
+至于`T34`和`new`中间的那个点「`.`」是个什么鬼,我们以后再解释。
+
+
+
+## 身份 Who
+
+几乎所有的技能都是「对人」的。
+比如「谁听牌我坑谁」,「自己加速、他家减速」,「专坑下家二十年」等等。
+要想在代码中表达这个「谁」的概念,就要用到`Who`这个 userdata 类型。
+
+`Who`和`T34`有一点区别:
+`T34`可以通过`T34.new`函数来创建,
+而`Who`无法在 Lua 里凭空创建,
+只能使用已经由系统创建好的的变量。
+其实我们已经用过好几次`who`类型的变量了 ——
+之前在`ondraw`函数中常用的`who`和`self`变量就都是`Who`类型的。
+每当系统在调用`ondraw`之前,都会设置好这两个全局变量:
+
+```lua
+function ondraw()
+ if who ~= self then
+ return
+ end
+
+ print("哇!")
+end
+```
+
+上面的写法是一种很常见的摸牌挂套路。
+首先,通过`who ~= self`判断`who`与`self`是否「不相等」。
+`~=`与`==`的作用刚好相反,在两侧不相等时得`true`,相等时得`false`。
+若`who`不等于`self`,则提前返回 ——
+这就导致了`ondraw`后半部分的代码只会在`who`为`self`的情况下执行,
+使得该技能只会影响自己的进张。
+
+`self`表示自己,那自己的下家、对家、上家又怎么表示呢?
+
+松饼提供了三个函数:`Who.right`, `Who.cross`, `Who.left`,
+分别可用于求出一个`Who`类型变量的下家、对家、或上家 ——
+只要把作为基准的`Who`变量作为参数传入即可:
+
+```lua
+function ondraw()
+ if who ~= Who.right(self) then
+ return
+ end
+
+ print("坑坑坑坑坑")
+end
+```
+
+三狗测试知以上人物在下家摸牌时输出「坑坑坑坑坑」。
+
+
+
+## 方法调用
+
+下面的两种写法作用是相同的:
+
+```lua
+Who.right(self) -- 写法1
+self:right() -- 写法2
+```
+
+这两种写法都表示「自己的下家」。
+「写法 2」只是「写法 1」的简略版本,没什么深奥的区别。
+这种带冒号的写法,
+等同于把冒号前面的 userdata 作为第一个参数传入冒号后面的函数。
+冒号后面的函数名,指代的是与这种 userdata 配套使用的那个函数 ——
+在上面的例子中,`self:right()`中的`right`实际代表`Who.right`。
+
+与某种 userdata 类型配套使用的函数,也叫作「方法」。
+不同的类型,有不同的方法。
+可以说,正是因为方法的不同,才使得类型得以不同。
+食物可以吃,可以煮;衣服可以穿,可以脱。
+因为可以吃,可以煮,所以才称得上是食物;
+因为可以穿,可以脱,所以才称得上是衣服。
+
+至于每一种类型具体都有哪些方法,
+可在需要时参考 [API 文档](/docs/editor/api/),无须刻意记忆。
+
+
+
+## 基本牌山干涉
+
+(TODO)
+[mount](/docs/libsaki/mount/)
+1. examples `lighta`
+2. simple logging
+
+
+
+## 练习题
+
+1) 预测各家摸牌前的输出:
+```lua
+function ondraw()
+ print(who:right():right() == self:left())
+end
+```
+
+自己摸牌前输出( ),
+下家摸牌前输出( ),
+对家摸牌前输出( ),
+上家摸牌前输出( )。
+
+下一讲:[控制流](/docs/editor/flow/)
+
diff --git a/docs/editor/var.md b/docs/editor/var.md
index a41a7a9..a311b94 100644
--- a/docs/editor/var.md
+++ b/docs/editor/var.md
@@ -136,7 +136,6 @@ print(3 + 2 * (2 - 3))
写下一行代码时,不光要考虑到这行代码是否满足眼下的需要,
更要考虑到将来是否可能会累死、是否可能会手滑。
人不能自己给自己挖坑。
-项目规模大到一定程度以后,人这种动物就会变得比想象中的要脆弱得多。
上面的例子中的表达式里用到了括号。
有些时候,即使是不影响计算的优先级,也会多加几个括号 ——
@@ -171,7 +170,7 @@ print(Emmm)
上面的代码输出 2333 和 66666,可见`emmm`和`Emmm`是两个不同的变量。
变量名可以由字母、数字、和下划线组成,同时不能以数字开头。
-虽然可以用大写,但习惯上一般只用小写变量名。
+虽然可以用大写,但习惯上(至少在 Lua 标准库中)一般只用小写变量名。
在三次元中,你可以给你家的狗起名为`if`,
但在 Lua 中这是非法的 —— `if`这个词已经被 Lua 保留了,
@@ -366,5 +365,5 @@ d = a == b
4) (附加题)上一题的代码执行后,`d`的值是什么?
-下一讲:(施工中)
+下一讲:[函数](/docs/editor/func/)
diff --git a/docs/girl.md b/docs/girl.md
index f4e05f2..59effe7 100644
--- a/docs/girl.md
+++ b/docs/girl.md
@@ -14,30 +14,31 @@ permalink: /docs/girl/
{% endfor %}
-
-
## 正片
-----
+
+
{% for girl in site.data.girls %}
-{{ girl.name }}
-{% for skill in girl.skills %}
- {{ skill.name }}
-
-{% endfor %}
-----
-{% endfor %}
-
+
diff --git a/docs/libsaki/mount.md b/docs/libsaki/mount.md
index 8b723f1..563e095 100644
--- a/docs/libsaki/mount.md
+++ b/docs/libsaki/mount.md
@@ -22,7 +22,7 @@ permalink: /docs/libsaki/mount/
这种直接改概率的方式是最容易想到的,
然而存在一个致命的问题,就是多个能力的叠加与兼容会变得复杂。
-例如,现在轮到A摸牌。A的技能规定:此时A有80%在概率自摸。
+例如,现在轮到A摸牌。A的技能规定:此时A有80%的概率自摸。
而另一个人物B的技能规定:此时A有90%的概率摸到B的铳牌。
那么结果A到底应该摸到什么呢?
diff --git a/docs/phil.md b/docs/phil.md
index 7ddf8de..49d4c62 100644
--- a/docs/phil.md
+++ b/docs/phil.md
@@ -55,8 +55,9 @@ permalink: /docs/phil/
1. 不支持犯规操作
1. 无役/振听时默默地没收和牌按钮
+ - 要啥提示,要啥提示,没算成诈和扣分就不错了
1. 模仿实体麻将
- 1. 不显示宝牌底色、振听提示等实麻中不存在的东西
+ 1. 不显示宝牌底色等实麻中不存在的东西
2. 自摸切/手切,鸣牌巡目只能在当时区分,过后只能自行记忆
3. 鸣牌/食和前应当没空犹豫,错过了就错过了
diff --git a/docs/rule.md b/docs/rule.md
index d8f1dd8..ae5328b 100644
--- a/docs/rule.md
+++ b/docs/rule.md
@@ -65,8 +65,10 @@ permalink: /docs/rule/
## 讨规约定
我们只接受两种有关规则的改动意见:
-- 现有规则和原作存在冲突
-- 现有规则过于稀有,不曾有人提及过
+1. 现有规则和原作主线剧情存在冲突
+ - 此处「原作」特指本篇、阿篇、慕篇漫画,
+ 不包括怜篇、动画、真人版、游戏
+2. 现有规则过于稀有,不曾有人提及过
-“和天凤不一样”等理由是不接受的。
+「和天凤不一样」等理由是不接受的。
diff --git a/docs/start.md b/docs/start.md
index ffe6594..adba88c 100644
--- a/docs/start.md
+++ b/docs/start.md
@@ -8,9 +8,7 @@ permalink: /docs/start/
不怕神对手,只怕猪队友——我们希望所有的项目参与者都能认真读完本文。
-
-
-## 1. 关于Git
+## 1. 关于 Git
松饼开发者必须熟悉Git。
如果没听说过、或不熟悉Git,可参考以下教程:
@@ -20,15 +18,13 @@ permalink: /docs/start/
2. 巩固补充(必修):[Ruheng的Git教程][git-adv]{:target="_blank"}
(学习时长:一至三天)
3. 深入(选修):[Pro Git (中文版)][pro-git]{:target="_blank"}
- (学习时长:长期)
-
-
+ (学习时长:长期)
## 2. 关于 Gitter
松饼开发者之间通过 Gitter 交流。
-Gitter 是一个聊天工具,可私信可群聊。
+Gitter 是一个聊天工具。
由于支持 Markdown 语法,并且可以和各类开发工具联动,
所以很适合有关编程的讨论。
Gitter 有网页版、桌面版、手机版,基本上什么系统都支持。
@@ -36,9 +32,7 @@ Gitter 有网页版、桌面版、手机版,基本上什么系统都支持。
- 松饼 Gitter 群链接:
[mjpancake]({{ site.data.link.gitter }}){:target="_blank"}
-
-
-## 3. 松饼是用什么做出来的
+## 3. 项目构成
「松饼」总共包含四个项目:核心库、客户端、服务器、主站。
四个项目关系如图。
@@ -54,32 +48,25 @@ GitHub 地址:
- [`rolevax/ih`][ih]
- [`mjpancake/mjpancake.github.io`][pages]
-
-
## 4. 开发环境的搭建步骤
见 [搭建开发环境](/docs/dev-setup/) 页面。
-
-
-## 5. 工作流程
+## 5. 大致工作流程与审查标准
-- 第一步,从`upstream/develop`创建新分支
- - `git fetch upstream`
- - `git checkout -b my-skill upstream/develop`
+- 第一步,从`develop`创建新分支
- 第二步,写代码,测试结果
- - 根据[松饼C++规范](/docs/cpp/)整理改动过的代码
- 第三步,提交并上传
- - `git commit -am "add xxxxx skill"`
- - `git push -u origin my-skill`
-- 第四步,创建 pull request 并等待审查
- - 合并目标是`develop`分支
+- 第四步,创建合并至`devleop`分支的 pull request 并等待审查
- 第五步,根据审查结果修改代码,提交上传并等待再次审查
- - `git commit -am "improve xxxxx skill"`
- - `git push`
- 重复第五步直到分支被合并
+明文审查标准:
+
+- [松饼 C++ 代码规范](/docs/cpp/)
+- [松饼 QML 代码规范](/docs/qml/)
+除明文标准外,还会有基于常识的考虑要素。
[lxf]: https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
[git-adv]: https://www.jianshu.com/p/072587b47515
diff --git a/feedback.md b/feedback.md
index 073623d..609363f 100644
--- a/feedback.md
+++ b/feedback.md
@@ -24,8 +24,6 @@ permalink: /feedback/
注意:
-- 有价值的 bug/错字 反馈可获得 0~500 贡献度
- - [贡献度是什么?](/contribute/)
- 如果是有关牌局的 bug,附上牌谱截图
- 截图需完整包含整张牌桌,不要裁剪
diff --git a/index.md b/index.md
index d657ef0..29b31ba 100644
--- a/index.md
+++ b/index.md
@@ -5,50 +5,90 @@ title: "松饼社区主站"
# 松饼麻雀简介
-「松饼麻雀」是一个 Saki 麻将模拟器,和官方游戏区别如下:
+「松饼麻雀」是一个 Saki 世界观麻将模拟器,
+由一群麻吧吧友和 AI 喵打共同制作。
+
+我们和官方游戏区别如下:
|-------------------|-------------------------|-----------|
-| 对比项目 | 松饼麻雀 | 官方游戏 |
+| | 松饼麻雀 | 官方游戏 |
|-------------------|-------------------------|-----------|
-| 平台 | 电脑/手机/平板 | PSP/PSV |
| 原作技能还原度 | 哇!!! | emmmm... |
-| 开放世界/可定制性 | 哇!!! | emmmm... |
-| 慕篇人物 | 哇!!! | emmmm... |
-| 慕篇规则 | 哇!!! | emmmm... |
-| 临海、有珠山人物 | 哇!!! | emmmm... |
+| 人物编辑器 | 哇!!! | emmmm... |
+| 慕篇、临海、有珠山人物 | 哇!!! | emmmm... |
+| 流年规则 | 哇!!! | emmmm... |
+| 支持平台 |Windows, Android, Linux, macOS, iOS|PSP, PSV |
|-------------------|-------------------------|-----------|
-
-总结起来,就是:
-> 一堆平台,五个「哇!!!」
+某截图:
----
-
+(准备中)
-# 如何入坑
+牌桌背景和人物头像可随意替换。
+目前的 UI 是临时凑合用的,将来会弃用传统的 2D 俯视牌桌,
+改用类似原作漫画的分镜式界面。
-入坑5大要素:
+# 下载松饼麻雀
-1. [注册](/signup/)
-2. 加群 253708512 (Q)
-3. [下载]({{ site.data.link.releases }})
-4. [看攻略](/docs/)
-5. [参与](/contribute/)
+- [点击进入下载页面]({{ site.data.link.releases }}){:target="_blank"}
+
+- 下载最上面的最新版即可
+- 以上链接为目前唯一的官方下载途径
+ - 通过其它途径下载的很有可能是魔改版
+- 系统要求:
+ - Windows: 7 或以上(不支持 XP 和 Vista)
+ - Android: 4.1 或以上
+ - Linux, macOS, iOS: 主流版本均可,需自行编译
+
+# 关于 ID
+
+- [注册松饼 ID](/signup/)
+
+# 讨论/提问
+
+- 官方企鹅群:253708512
+ - 加了这个群,就可以愉♂悦地讨论、提问了 —— 还能及时获得各种一手情报。
+- 意见、建议、或 bug 报告:前往[「反馈」](/feedback/)页面。
+- 松饼麻雀全栈开源,欢迎 dalao 参与开发
+ —— 详见下方[「开发者 RTFM 系列」](#rtfm)一节。
+
+# 食用手册
+
+- [能力表](/docs/girl/)
+- [麻将规则](/docs/rule/)
+- [设计哲♂学](/docs/phil/)
+- [还原度对照表](/docs/target/)
+
+# 人物编辑器
+
+「松饼人物编辑器:从入门到欧耶」系列教程:
+
+- [搞起](/docs/editor/start/)
+- [数据类型](/docs/editor/var/)
+- [函数](/docs/editor/func/)
+- [局部变量](/docs/editor/local/)
+- [userdata](/docs/editor/userdata/)
+- [控制流](/docs/editor/flow/)
+- (施工中)
+
+文档:
+
+- [范例](/docs/editor/examples/)
+- [API 文档](/docs/editor/api/)
+
+# 开发者 RTFM 系列
+
+首次参与开发松饼,看这个:
+
+- [如何开始参与开发](/docs/start/)
+
+各种参考资料:
+
+- [搭建开发环境](/docs/dev-setup/)
+- [Libsaki 代码导读](/docs/libsaki/)
+- [松饼 C++ 代码规范](/docs/cpp/)
+- [松饼 QML 代码规范](/docs/qml/)
----
-
-
-# 配置要求
-
-|-----------|---------------------------------------|
-| 平台 | 要求 |
-|-----------|---------------------------------------|
-| Windows | Windows 7 或以上(不支持 XP 和 Vista)|
-| Android | Android 4.1 或以上 |
-| Linux X11 | 依赖 Qt 5,需要自行编译 |
-| macOS | 依赖 Qt 5 和 Xcode,需要自行编译 |
-| iOS | 依赖 Qt 5 和 Xcode,需要自行编译 |
-|-----------|---------------------------------------|
diff --git a/signup-pass.md b/signup-pass.md
index 44b6159..aead9c1 100644
--- a/signup-pass.md
+++ b/signup-pass.md
@@ -5,6 +5,6 @@ permalink: /signup-pass/
---
- 喜大普奔!账号注册成功。
-- **下一步**:回到[入坑步骤](/#newbie),继续入坑。
+- 回到[首页](/)。
diff --git a/signup.md b/signup.md
index ec9f29a..73d2c80 100644
--- a/signup.md
+++ b/signup.md
@@ -125,8 +125,8 @@ table td, table td * {
## 松饼在线功能使用协议
1. 注册账号即视为同意本协议。若不同意,则不应当注册。
-1. 松饼麻雀处于删档测试阶段。平台有权随时无理由删除或修改任何数据。
+1. 松饼麻雀处于删档测试阶段,平台有权随意改动任何数据。
1. 平台对产品和服务不提供任何质量保证。
出现故障,不保证修复;出现损失,无义务赔偿。
-1. 平台不提供任何隐私或安全的保障,对于用户数据(包括密码在内)的泄露不负任何责任。
+1. 平台不提供任何隐私或安全的保障,用户须自行承担数据泄漏的风险。
1. 平台有权随时无理由暂停或终止一切运维。