文明/文明IV/Modding/教程/Python教程
Python可以用來在文明4中實現很多令人驚奇的事情,但前提是你必須知道怎麼做。現在,雖然我可能不是寫這個教程的最佳人選,但我感覺我對用它來改變遊戲的方式非常熟悉。請隨時編輯我在這裡寫的任何內容,因為這個教程遠未完善。該教程也在CFC 這裡。我會嘗試更新維基百科上的任何更新,儘管很明顯那裡的格式更嚴格一些。
如果你想了解一些關於python的知識,我建議你檢視維基百科條目和python網站
簡單介紹一下python在文明4中的能力
Python可以
- 用來製作複雜的指令碼,在觸發器觸發時導致事件發生。例如,你可以讓它在當你佔領一個宗教的聖城時,所有信仰該宗教的文明都向你宣戰。
- 用來編輯介面。幾乎所有的遊戲介面都是由python動態生成的,可以在python中編輯。你可以製作新的按鈕,更改文明百科的佈局,更改科技樹的生成方式......甚至,如果你願意,可以在螢幕角落製作一隻跳舞的小豬 - 伴隨著音樂(雖然我相信還沒有人嘗試過,但我確信這是可以實現的)。這方面有一些限制 - 例如,滑鼠懸停文字更適合使用SDK。
- 用來生成新的地圖型別。我自己沒有嘗試過,所以這個教程可能不會涵蓋得太好。
- 用來編輯AI......但我建議使用SDK,因為它可能會節省大量時間!
Python不能
- 完全按照你想要的方式使用。雖然你可以用它做很多事情,但有些事情你就是做不到。這確實非常令人沮喪,但這是你必須學會接受的事情。你能做的事情數量驚人,所以不要抱怨。希望隨著SDK的釋出,更多經驗豐富的程式設計師會增強python改變遊戲運作方式的能力。
還在讀?很好!
現在,我建議你首先瀏覽一下GBM的python教程,它簡要概述瞭如何用python程式設計。另外,如果你還沒有,請檢視python網站,那裡有大量關於python的資訊(毫不奇怪)。最後,我會檢視一下由Jon (Trip) Shafer, Firaxis編寫的這個python教程,你可能會發現他的教程比我的更好,畢竟,他最初編寫了其中很大一部分程式碼。
正如你所知,在python中,有幾種不同的“事物”型別:整數、浮點數、字串和布林值。你可能也知道“指標”。我第一次接觸python的時候並不知道,所以我在這裡提醒你一下。
基本上,指標是一個遊戲實體。它可以是單位、地塊(方格)或玩家的形式。在預設的python程式碼中,以及在許多modder的程式碼中,一個變數如果以“p”開頭,則表明它是一個指標。因此,pUnit將定義遊戲中單個單位,pPlayer將定義單個玩家。
同樣地,如果一個變數以“i”開頭,它很可能是一個整數(int)變數,而“b”則是一個布林值(bool)變數。例如,iPlayer很可能是一個玩家的個人ID號,而不是玩家的指標。
這有時會讓人困惑,因為大多數指標都有與之密切相關的整數。這種命名方法有助於避免在像python這樣的語言中出現混淆,因為變數不需要宣告,但是這只是一個指導原則,僅僅因為一個變數的命名方式就像它是某種型別的變數,它並不一定就是那種型別。
我還想在這裡說明一下“型別”。在大多數xml條目中,你需要在“型別”欄位中輸入一些內容。這個欄位是與python的非常重要的連線,但必須轉換為整數才能正常工作。有一個函式你會發現自己一遍又一遍地使用它,所以我認為應該在這裡提到它。這個函式會找到對應於型別的整數 - 因為API(即將到來)中的大多數函式都需要型別的整數形式,所以它非常有用。例如
gc.getInfoTypeForString("TECH_MYSTICISM")
將返回對應於“神秘主義”科技的整數,因為它是相關xml檔案中的第一個條目,因此預設值為0。
gc.getInfoTypeForString("RELIGION_TAOISM")
將返回預設值6,因為它是列出的第7個宗教。
如果你現在還不明白最後一點,別擔心 - 希望在閱讀下一部分時會變得清晰。
文明4 API是所有與實際遊戲互動的特定於文明4的函式列表。API有兩個版本。第一個版本,由Locutus編寫,可以在這裡找到,第二個版本,由GBM編寫,可以在這裡找到。Locutus的API已更新至1.60補丁,因此我建議你使用那個版本。
現在,在過去的一個月左右的時間裡,我在論壇上回答有關python的問題時,我注意到很多人在閱讀API時遇到了困難。解釋函式的功能可能很困難,但是API確實提供了一些提示,如果你願意閱讀它們。
我將以Locutus的API為例,因為我覺得它的介面更好,所以開啟它!
首先,我們有類。它們列出了所有可以對特定實體或指標執行的函式。例如,CyUnit列出了所有可以在單位實體(遊戲中的單位)上使用的函式。類列在左上角的框架中。你會注意到,一些類旁邊有一個“+”符號。這些類用於直接從xml檔案中的物件獲取特定資訊。
現在我們有了型別。它們是從xml檔案提取的不同型別。顯示的整數是預設值,雖然你可以使用它們,而且程式碼很可能能執行,但我建議不要這樣做,因為如果在將來的補丁中更改了xml的順序,你的程式碼就會崩潰。相反,我建議使用gc.getInfoTypeForString(""),如上所示,因為這樣更相容補丁。
最後,我們有了函式。每個類都有自己的一組函式,這些函式只能用於該類,不能用於其他類。如果你試圖從一個類中獲取一個函式,並將其用於另一個類,那麼它將無法工作。函式是API的主要部分,是你想要了解的東西。
現在,有很多不同的函式。大多數函式在遊戲中不“執行”任何操作,而是從你的指標獲取一個值,你可以用它來進行計算。如果你看一下函式的左邊,它會告訴你這個函式返回什麼。例如,如果你使用
BOOL CyPlayer.canChangeReligion()
它不會設定玩家能夠改變宗教,而是會返回一個 BOOL,一個真或假值,取決於玩家是否可以改變宗教。明白我的意思嗎?它不“執行”任何操作,對吧?
函式可以返回以下型別的值:
- Bool - 真或假,1 或 0
- Int - 整數值(可以為負數)(例如 256)
- Float - 浮點數(例如 1.3423)
- String - 字串(“貓坐在墊子上”)
- Turple - 列表([1, 4, 2, 8, 2])
- Void - 參見下文
那些“執行”操作的函式會返回“VOID”,這意味著它們是設定而不是獲取資料。這些函式實際上是最重要的,因為沒有它們你無法做太多事情,不幸的是,它們的數量不夠多,無法完成你想要的所有事情。抱歉,但這就是現狀。
所以,你知道一個函式返回什麼,但這並不是你需要知道的全部。你還要知道需要提供什麼資訊才能讓它返回這些資料。有些函式不需要任何輸入。
CyUnit.canMove()
例如,除了要檢查哪個單位可以移動之外,它不需要知道任何其他資訊(單位指標應該放在 CyUnit 的位置)。然而,大多數函式並不像這樣簡單,它們需要輸入才能產生輸出。
舉個例子,
CyUnit.setHasPromotion(PromotionType eIndex, BOOL bNewValue)
這個函式接收兩個引數(輸入):你想要賦予單位的晉升型別,以及一個布林值,表示是否要獲取或刪除晉升。舉個例子,
pUnit.setHasPromotion(gc.getInfoTypeForString("PROMOTION_COMBAT1"), 1)
將賦予指標 pUnit 戰鬥 1 晉升。請注意,在這種情況下,使用晉升的整數值很重要,因為當函式要求型別時,它實際上想要一個整數……別問為什麼!幸運的是,如果你在函式中輸入了錯誤的引數,Python 會在嘗試執行函式時告訴你。更多內容將在除錯部分介紹!
CyGlobalContext
[edit | edit source]在檔案中通常縮寫為 gc,這可能是最有用的類,因為它包含了所有與文明 4 相關的通用函式。GlobalContext 的獨特之處在於它不需要用指標呼叫,而是一個獨立的類,用於獲取資訊。
它有許多有用的用途
- 正如我之前所說,你可以用它從型別獲取整數。例如,
gc.getInfoTypeForString("TECH_MYSTICISM")
將獲取神秘主義的整數值。
- 你可以用它從整數 ID 獲取指標。例如,
gc.getPlayer(0)
將返回 ID 為零的玩家的 pPlayer 指標。
- 你可以用它從 xml 檔案獲取資訊。例如,
gc.getPromotionInfo("PROMOTION_COMBAT1")
將返回戰鬥 1 晉升的指標,然後可以與 CvPromotionInfo 一起使用,以獲取有關該特定晉升的資訊。
- 一個常見的用法是獲取活動玩家指標,它將返回當前輪到誰的玩家的指標。
gc.getActivePlayer()
- 最後一個主要用途是獲取某一特定事物的例項數量。例如,
gc.getNumPromotionInfos()
將返回遊戲中可用的晉升數量。這對於你想要迴圈遍歷晉升並檢查單位是否擁有它們,並在擁有時啟用一個新函式非常有用。
雖然 CyGlobalContext 有其他用途,但它們實在太多,這裡無法一一列舉。我已經盡力列出了我認為最主要的用途。
事件
[edit | edit source]事件是由於某些觸發器而發生的事情。觸發器的數量是固定的,這在一定程度上限制了模組作者,但這些觸發器可以滿足大多數指令碼的需求。如果你開啟 CvEventManager.py,事件觸發器從第 193 行執行到第 747 行(1.52 補丁)。有近 60 個不同的觸發器可以使用,從 onUpdate(每幀執行,可能每秒大約 30 次)到 onGameStart(僅執行一次,在遊戲開始時執行)。
大多數觸發器都有與之關聯的引數。這些引數儲存在 argsList 中。在大多數事件標題下,這些引數都已定義。通常它們的作用相當明顯。
也許在觸發器上新增事件的最簡單方法就是將事件新增到事件管理器中。這對於小型模組來說可以奏效,但會帶來一些相容性問題。更好的方法是建立你自己的 CvCustomEventManager 檔案。我推薦 Dr Elmer Jiggle 的事件管理器(可以在 這裡找到)。它一開始可能有點難理解,但如果你能用它,它絕對物超所值。要檢視其執行示例,可以檢視 TheLopez 的任何 ModComps(可以在 這個論壇中找到)。
需要注意的事項
- onEndPlayerTurn 觸發器不會在玩家回合結束時發生,而是在玩家回合開始結束時發生,在所有城市都完成建造等操作之後。如果你想在玩家回合結束時執行一個事件,你可能需要修改一些程式碼,以便在下一個玩家回合開始時執行它。看起來 onBeginGameTurn 和 onEndGameTurn 也類似,儘管它們都發生在遊戲回合結束時,而不是像玩家回合一樣發生在開始時。感謝 Kael 指出這一點。
示例
- 例如,如果你想在每個遊戲回合開始時(即在第一個玩家回合開始時)在每個玩家的螢幕上顯示一條訊息,你可以在事件管理器中用以下程式碼替換這段程式碼
def onBeginGameTurn(self, argsList): 'Called at the beginning of the end of each turn' iGameTurn = argsList[0] CvTopCivs.CvTopCivs().turnChecker(iGameTurn)
以下程式碼:
def onBeginGameTurn(self, argsList):
'Called at the beginning of the end of each turn'
iGameTurn = argsList[0]
CyInterface.addImmediateMessage("You have just started a new turn", "") # Adds the message "You have just started a new turn" with no sound attached.
CvTopCivs.CvTopCivs().turnChecker(iGameTurn)
注意:在製作正式的模組時,你不應該像這樣簡單地向事件管理器新增內容,因為它會導致相容性問題。請檢視上面連結的自定義事件管理器。
介面
[edit | edit source]正如我在引言中提到的,幾乎所有 GUI 都是動態建立的,要麼是在你進入相關螢幕時建立,要麼是在遊戲開始時建立。幾乎所有 GUI 都可以進行模組化。模組化介面的檔案位於 .../Assets/Python/Screens 中。
需要注意的事項
- 在介面中放置專案時,你輸入的 x 和 y 座標將對應於專案的左上角。
- 請記住,解析度可能會發生變化。通常情況下,根據解析度更改介面的顯示方式可能是個好主意。要查詢 X 和 Y 解析度,可以使用以下程式碼:
CyGInterfaceScreen.getXResolution() or CyGInterfaceScreen.getYResolution()
- 如果一個專案需要一個名稱,該名稱必須是該專案獨有的,否則就會發生奇怪的事情。
- techchooser 指令碼的編寫方式使得對其進行模組化非常困難。techchooser 並不是在每次載入螢幕時都會生成,而是在遊戲開始時生成,然後僅在遊戲中進行顏色更改。為了防止這種情況在遊戲中發生,並確保 techchooser 在遊戲執行時顯示你對其進行的模組,我建議你註釋掉第 72 行(screen.setPersistent(True))。這將使 techchooser 在開啟時不斷重新生成,儘管這可能會使你的電腦速度略微降低,但它應該能更好地工作。但是,由於 techchooser 模組的生成方式,你可能需要重新啟動遊戲才能看到任何更改。
除錯
[edit | edit source]如果有人能檢查一下這一部分,我會很感激,因為我不確定它是否完全準確,而且由於我將在接下來的幾個月裡無法使用電腦,所以我無法測試它。
當指令碼無法正常工作時,每個人都必須進行除錯,因為很容易犯一個小錯誤,導致整個程式碼毫無意義。除錯的第一步是開啟遊戲中的除錯選項。為此,開啟 Civilization4.ini(請確保備份),並將以下條目更改為以下值
HidePythonExceptions = 0 ShowPythonDebugMsgs = 1 LoggingEnabled = 1 MessageLog = 1
這將啟用遊戲中的 Python 彈出視窗,並將所有錯誤和訊息列印到你的 My Documents/My Games/Civilization 4/Logs 目錄中。在除錯時要檢視的三個重要日誌是 PythonDbg、PythonErr 和 PythonErr2。
常見的錯誤訊息及其原因
[edit | edit source]通常在日誌中,錯誤會附帶一個回溯資訊。這個回溯資訊列出了受錯誤影響的所有檔案,以及錯誤發生的行號。最後一行通常是您最感興趣的,因為這是錯誤發生的地方。有時您需要回溯幾步,因為錯誤可能不在最後一行,但通常都在最後一行!
語法錯誤
[edit | edit source]這些主要是輸入錯誤,例如漏掉了 ":",空格錯誤,或者括號不匹配。遊戲通常會在您載入遊戲時發現這些錯誤。錯誤日誌會用一個小的 ^ 符號來指示語法錯誤的位置。
引數錯誤
[edit | edit source]如果您嘗試在整型值上使用為指標設計的函式,您將獲得一個型別錯誤。轉到指定行,檢查您使用的函式是否有效。通常它會說明它期望的函式型別以及您提供的函式型別。注意:有些類在函式中需要 (),有些不需要。如果您遇到型別錯誤,這可能是原因。
型別錯誤
[edit | edit source]當您傳遞給函式的引數過多或過少時,就會發生這些錯誤。您需要確保傳遞給函式的引數數量與它需要的引數數量一致,否則函式在執行時會丟擲錯誤。
名稱錯誤
[edit | edit source]這意味著您嘗試使用遊戲無法識別的內容。例如,如果您在沒有先宣告 b 的情況下輸入 a = b,計算機就無法將值賦給 a。請記住 a=b 和 b=a 的含義不同。此外,請確保您沒有將 "==" 用在需要 "=" 的地方,反之亦然。
有時您會遇到 "Argument referenced before assignment" 錯誤。我不知道這是否屬於名稱錯誤,或者是否需要單獨的分類,但基本上它類似於名稱錯誤,只是您在程式碼中稍後定義了 "a"。
"List index out of range"
[edit | edit source]當您嘗試引用列表、元組或字典中不存在的索引時,就會發生這種情況。這個錯誤可能很難解決,您可能需要使用本節下一部分中描述的方法來檢視具體問題所在。
目前,我已經能想到的所有錯誤訊息就這些了。我確定我遺漏了一兩個錯誤,如果您發現任何錯誤,請隨時提出,我會將其新增到這裡。正如我在開頭所說,我不確定這些資訊的準確性,但應該沒問題。
程式碼行為異常
[edit | edit source]您編寫了程式碼,它沒有錯誤,可以正常執行... 但它在遊戲中沒有產生您期望的結果。這可能有多種原因。
首先,如果您認為一段程式碼應該對遊戲產生影響,請透過檢視 API 來確保它確實生效,並檢查它是否是一個 VOID 函式。在剛開始學習時,很容易犯錯誤,使用其他函式以為它們會做某些事情,實際上它們只是檢索資訊。
其次,如果一切看起來都正確,您需要開始新增除錯資訊。這部分內容將您帶回到 Python 程式設計的最初階段,當時您告訴計算機列印 "hello world"。您需要做的是讓計算機列印一條訊息,告訴您程式碼中某個特定點的某個值的具體內容,並將它與您認為它應該是什麼進行比較。例如,以下程式碼將在除錯日誌中列印 "a=b" 如果 a=b,否則列印 a 和 b 的值。
if a == b: print "a=b" else: print a print b
在除錯日誌中解析這些資訊可能很困難(通常您會有很多很多數字),所以您可以使用更高階的訊息。
if a == b:
print "a = b, a and b are %d, and %d"%(a,b))
else:
print("a = %d"%(a))
print("b = %d"%(b))
%d 將引用 " " 後面 % 後面的數字。如果您想在其中放置字串,您需要使用 %s。這可以為您提供關於程式碼內部執行情況的詳細資訊,並且希望透過這些資訊,您能夠看到程式碼中存在的問題。
其他
[edit | edit source]此頁面包含有關 Civ 4 Python 的其他內容,這些內容在其他帖子中沒有介紹,而且乍一看並不明顯。其中一些內容是粉絲自制的,建立了一些實現非常複雜功能的快捷方式。
PyHelpers.py
[edit | edit source]大多數 Python 檔案都會匯入此檔案。它基本上為一些更復雜的函式添加了一些快捷方式。如果您在 API 中找不到您想要的內容,那麼此檔案可能會幫到您,儘管它只建立了快捷方式,仍然遵循 API。
CvGameUtils.py
[edit | edit source]此檔案用於決定某些事情,例如可以/不能建造什麼。它可以用來中斷一些基本的遊戲功能。通常每個函式都會返回 "False",但如果您在某些特定條件下讓它返回 "True",例如,就可以從可用單位列表中移除該單位。例如,您可以使用它讓擁有奴隸制公民權的文明能夠建造奴隸單位。我建議您親自檢視一下,看看您在其中擁有多少許可權。
指令碼資料
[edit | edit source]如果您想新增有關遊戲世界某些部分的額外資訊,您需要指令碼資料。例如,如果您想讓單位在每次戰鬥時消耗 "彈藥",然後必須返回到有兵工廠的城市進行補給,或者您想讓地塊在沒有道路的情況下被過多單位通行後變得泥濘,您需要指令碼資料。
如果您想嘗試使用指令碼資料,我建議您使用 Stone-D 出色的 SD-Toolkit。此工具包允許您將資料片段附加到遊戲的各個部分。每個部分都必須使用唯一的 mod 名稱標識(為了相容性)。
注意:Teg_Navanis 在 CFC 上的這篇帖子 中釋出了該工具包的改進版本。這個版本比預設版本更快,並且修復了預設版本中的一些小問題。
操作按鈕
[edit | edit source]talchas 釋出了一個名為 Action Button's Utility Mod 的模組,它是一個模板,允許你新增按鈕到遊戲介面,這些按鈕在被按下時會執行自定義函式。AI 不會知道這個模組的存在。
這個模組同樣由 talchas 建立,它是一個模板,你可以透過適當的修改來讓炮兵的運作方式與文明3中的炮兵一致,無需任何變通方案。但是,AI 的缺陷仍然存在。
雖然我還沒有親身嘗試,但是 Dr Elmer Jiggle 建立了一個模組,允許你在模組的 .ini 檔案中新增變數。 點選這裡獲取