---
# System prepended metadata

title: 'HW2: RPG Game FAQ'

---

# HW2: RPG Game FAQ


## Output Format

1. 在*S2*: select targets時，印出的candidates索引中會跳過死掉的units嗎？

已死的units並不會被包含在candidates中，而給定N個candidates，索引則從0算到n-1。以下為例：

**Given**: 4個Enemy units [A, B, C, D]，其中B, D死亡。
**When**: 你使用Waterball（攻擊對象：一位）
**Then**: 輸出以下
`Select 1 targets: (0) [2]A (1) [2]C`

## AI

1. 如果AI的`selectActions`方法，回傳了不合法的action (e.g.,魔力不足以執行該action)，該怎麼辦？

你**只能傳合法Actions的索引**給他做選擇。

例如：如果AI具有四個Actions，其索引為 `[0,1,2,3]`，並且AI當下的魔力只足夠於使用0或3，則你必須傳入`[0,3]`進`selectActions` 方法中。在此例中AI則會回傳0或3其中一個索引作為他的選擇。

2. 根據 spec 上寫，"The assumption of these AI units is that the selectAction and selectTarget methods are called only once in the unit's turn."，是否在以下情形也要 call selectTarget？
    (a) AI 使用全體技（如：Fireball）、AI 使用沒有目標的技能（如：Summon）、AI 使用只能以自己為目標的技能（如：SelfHealing）
    (b) AI 使用 Cheerup 要選擇 3 個目標，但場上只剩下 2 個合法目標，此時是否仍要 call selectTarget(2,2) ？

這些情況皆不需要呼叫`selectTarget`。
只有要求specific targets的技能和場合才需要呼叫`selectTarget`唷。

> 規格在S2中有提到說在(b)提及的場合下RPG會自動選擇targets。


## OnePunch

1. 為了使用`OnePunch`，我該如何取得`OnePunch`造成的damage？

**你無法直接地取得其damage。**

`OnePunch`具有兩個方法，其中你可以透過`int getMpCost()`來獲得此技能所需的魔力消耗。而另一個則為：
```java=
void perform(Target target)
```

其中`Target`的Interface定義如下：
```java=
public interface Target {
    void takeOnePunchDamage(int damage);
}
```

你不能直接取得`OnePunch`的damage值，你必須依照他方法所示，傳一個`Target`實體進去其`perform`方法，而`OnePunch`則會在執行`perform`時，把damage再傳入`Target`實作的`takeOnePunchDamage`方法中。

2. 如果讓`Unit`類別實作`OnePunch`所需的`Target`介面，是不是就不符合**OCP**了呀？

沒錯，因為這樣一來，當你要把`OnePunch`這個技能刪除時，你也須要將`Unit`實作`Target`的部分也一併刪除。

Tips: 先當作規格裡沒有`OnePunch`來設計你的程式，等其他九個技能都實作完之後，再來想`OnePunch`的設計，可能你就會突然想到一些辦法來處理此「**外部依賴造成的外力**」。


## Self-Explosion

Q: 請問Ｃ會不會在ＡSelfExplosion 的途中(B die 的下一行)補血 .
也就是Ｃ會不會因為curse了Ｂ, 而在Ａ 的 SelfExplosion 中活下來。
還是SelfExplosion結算完才會處理curse的回血。

A: 

Curse目標的Unit(B)死亡的當下就會啟動Curse的效果(A回血)。

而SelfExplosion的自殺效果（turn A's HP to zero）是他造成所有Unit傷害之後才奏效的。


如以下Out所示，(Curse奏效的時機點已用"Curse Effect..."印出)

```
[1]Hero's turn (HP: 500, MP: 500, STR: 100, State: Normal).
Select an action: (0) Basic Attack (1) SelfExplosion (2) Curse
[1]Hero uses Curse on [2]Slime1.
[2]Slime1's turn (HP: 100, MP: 10000, STR: 50, State: Normal).
Select an action: (0) Basic Attack
[2]Slime1 attacks [1]Hero.
[2]Slime1 causes 50 damage to [1]Hero.
[1]Hero's turn (HP: 450, MP: 400, STR: 100, State: Normal).
Select an action: (0) Basic Attack (1) SelfExplosion (2) Curse
[1]Hero uses SelfExplosion on [2]Slime1.
[1]Hero causes 150 damage to [2]Slime1.
[2]Slime1 dies.
Curse Effect (Hero's HP + 10000)
[1]Hero dies.
You lose.
```

## Curse

Q: 如果A curse B之後，A先死了，之後B死的時候A會回血嗎？
A: 不會唷，死掉之後Curse就不會發揮作用了。（規格尚未講得十分清楚，這部分有其他疑慮請各位同學直接以測資為主，測資中的corner cases並不多。）



## Cheerup
施展Cheerup會對三名Allies，進入Cheerup狀態。Cheerup狀態下的Unit其在施放能造成傷害的Action時（Basic Attack, Waterball, Fireball, SelfExplosion, OnePunch），此Action傷害皆會加50。


[Given] 

T1 = [ Hero, A, B ]

[When]
Hero對A, B施展了Cheerup

[Then] 

在Cheerup狀態下（三回合內）
若A或B施展了Fireball (或是其他有傷害性的Actions)
那就會對所有enemy造成 50+50 = 100 的傷害

## OCP

1. 如果讓`Unit`類別實作`OnePunch`所需的`Target`介面，是不是就不符合**OCP**了呀？

沒錯，詳細請往上找尋`OnePunch`小節。

2. enum是不是本身就不具有OCP？

沒錯，因為新增新的type時，你必須改變舊有的enum內部程式，因此不符合OCP。enum只是一個常數空間而已，當你真的需要OCP時，就該往多型（polymorphism）的方向做思考，以及踏踏實實地善用設計重構三步驟（詳細請看規格中的TA Tips小節）。

3. OCP的評分標準：
- [What are not OCPs](https://github.com/Fundamental-OOP/HW2-RPG-BATTLE/tree/main/src/tutorials/ocp/whatarenotocp)
- [OCP Clarification](https://hackmd.io/rFlV4kBGRROFkyI1yuo6JA)

## 該怎麼寫...

1. 這一題怎麼難度又翻倍了？？該怎麼下手比較好？？

我的建議是，**把它放在作業Priority Queue的Top，因為這一題可能比想像中還要多花一點時間。** 而早一點開始接觸這個作業，你才能較早享受到「潛意識思考」的幫助 :)，慢慢打好這一場持久戰。

最好的做法是用兩到三天的時間理解規格並把理解**專心且優雅地**畫在類別圖中，然後試著照圖實作，趕緊找到自身盲點去修正類別圖。而其中如果規格有一些地方無法釐清請直接上NTU Cool發問吧 :)！

2. 好煩躁啊啊啊

如我一開始所說，軟體工程解決的並不是「困難」的事，而是「複雜」的事。RPG中的每一個技能都不需要一個特別聰明高效率的算法，但每一個技能都會帶來新的**設計外力（Force)**。

厲害的軟體設計師，會看得出來這個外力的形狀，並能把軟體依照外力的形狀做開發。讓外力優雅地活在我們開發的軟體之中。

在我們熟悉這個技能之前，會很容易被這些外力戳得心疲力盡，但這是必須的痛楚。因此要寫好這個作業，打的是一個持久的心態戰爭。你很有可能會每多支援一個新的技能，就必須重構一部分你的程式，而每一次重構你都必須要停下腳步，意識到該外力的長相為何，為什麼你之前沒有考慮到這一點？

而使用UML做Modeling，不斷同步實作和設計圖，只是維持良好設計視角和心態的一個手段。其圖上呈現的形式（你畫的東西），也許並不是這麼重要，那只是和腦袋的一個長期的相處過程。
