# Advanced Banners

Advanced Banners let you define responsive, context-aware banner ad layouts that adapt to device type, screen orientation, and screen size. Unlike regular banners (which support only top/bottom positioning), Advanced Banners allow you to place multiple banners at arbitrary positions on the screen and automatically switch layouts when conditions change.

### Checking Support

{% tabs %}
{% tab title="Godot 3.x" %}

```gdscript
if Bridge.advertisement.is_advanced_banners_supported:
    # Advanced Banners are available
    pass
```

{% endtab %}

{% tab title="Godot 4.x" %}

```gdscript
if Bridge.advertisement.is_advanced_banners_supported:
    # Advanced Banners are available
    pass
```

{% endtab %}
{% endtabs %}

### Usage

#### Method 1: Explicit API Call

Show and hide Advanced Banners directly from your game code.

{% tabs %}
{% tab title="Godot 3.x" %}

```gdscript
# Show banners for a specific placement
Bridge.advertisement.show_advanced_banners("main_menu")

# Hide banners
Bridge.advertisement.hide_advanced_banners()
```

{% endtab %}

{% tab title="Godot 4.x" %}

```gdscript
# Show banners for a specific placement
Bridge.advertisement.show_advanced_banners("main_menu")

# Hide banners
Bridge.advertisement.hide_advanced_banners()
```

{% endtab %}
{% endtabs %}

If `placementFallback` is set in the config, you can call without arguments:

{% tabs %}
{% tab title="Godot 3.x" %}

```gdscript
Bridge.advertisement.show_advanced_banners()
```

{% endtab %}

{% tab title="Godot 4.x" %}

```gdscript
Bridge.advertisement.show_advanced_banners()
```

{% endtab %}
{% endtabs %}

#### Method 2: Automatic via Platform Messages

Advanced Banners automatically react to platform messages. When you call `Bridge.platform.send_message()` or `Bridge.platform.send_custom_message()`, the system checks if a matching placement exists in the config and triggers it.

{% tabs %}
{% tab title="Godot 3.x" %}

```gdscript
# This will automatically show banners if "level_paused" placement is configured
Bridge.platform.send_message(Bridge.PlatformMessage.LEVEL_PAUSED)

# This will hide banners if "level_resumed" has action: "hide"
Bridge.platform.send_message(Bridge.PlatformMessage.LEVEL_RESUMED)

# Custom messages work the same way
Bridge.platform.send_custom_message("shop_opened")
```

{% endtab %}

{% tab title="Godot 4.x" %}

```gdscript
# This will automatically show banners if "level_paused" placement is configured
Bridge.platform.send_message(Bridge.PlatformMessage.LEVEL_PAUSED)

# This will hide banners if "level_resumed" has action: "hide"
Bridge.platform.send_message(Bridge.PlatformMessage.LEVEL_RESUMED)

# Custom messages work the same way
Bridge.platform.send_custom_message("shop_opened")
```

{% endtab %}
{% endtabs %}

This is the recommended approach because it ties banner visibility to your game's lifecycle without extra code.

#### Tracking State

{% tabs %}
{% tab title="Godot 3.x" %}

```gdscript
# Check current state
var state = Bridge.advertisement.advanced_banners_state
# Possible values: "loading", "shown", "hidden", "failed"

# To track state changes, connect to the signal
func _ready():
    Bridge.advertisement.connect("advanced_banners_state_changed", self, "_on_advanced_banners_state_changed")

func _on_advanced_banners_state_changed(state):
    match state:
        "loading":
            # Banners are being loaded
            pass
        "shown":
            # Banners are visible
            pass
        "hidden":
            # Banners were hidden
            pass
        "failed":
            # Banners failed to load
            pass
```

{% endtab %}

{% tab title="Godot 4.x" %}

```gdscript
# Check current state
var state = Bridge.advertisement.advanced_banners_state
# Possible values: "loading", "shown", "hidden", "failed"

# To track state changes, connect to the signal
func _ready():
    Bridge.advertisement.connect("advanced_banners_state_changed", Callable(self, "_on_advanced_banners_state_changed"))

func _on_advanced_banners_state_changed(state):
    match state:
        "loading":
            # Banners are being loaded
            pass
        "shown":
            # Banners are visible
            pass
        "hidden":
            # Banners were hidden
            pass
        "failed":
            # Banners failed to load
            pass
```

{% endtab %}
{% endtabs %}

### Automatic Behavior

#### Fullscreen Ad Coordination

Advanced Banners are automatically hidden when an interstitial or rewarded ad starts (loading or opened) and automatically restored when the ad finishes (closed or failed). No additional code is needed.

```
Interstitial starts → Advanced Banners hidden
Interstitial ends   → Advanced Banners restored

Rewarded starts     → Advanced Banners hidden
Rewarded ends       → Advanced Banners restored
```

#### Responsive Re-evaluation

When the screen orientation changes or the window is resized, the system automatically re-evaluates conditions and switches to a better-matching variant if one exists. This happens with a 200ms debounce to avoid excessive updates.

For example, if a user rotates their phone from portrait to landscape, and your config has different layouts for each orientation, the banners will seamlessly switch.

### Complete Example

#### Config

```json
{
    "advertisement": {
        "advancedBanners": {
            "placementFallback": "gameplay_stopped",
            "gameplay_started": {
                "action": "hide"
            },
            "gameplay_stopped": {
                "action": "show",
                "default": [
                    { "width": "300px", "height": "250px", "bottom": "10%", "right": "5%" }
                ],
                "mobile:portrait": [
                    { "width": "320px", "height": "50px", "bottom": "0", "left": "0" }
                ],
                "mobile:landscape": [
                    { "width": "300px", "height": "250px", "top": "50%", "right": "0" }
                ],
                "desktop:w>1200": [
                    { "width": "160px", "height": "600px", "top": "10%", "left": "1%" },
                    { "width": "160px", "height": "600px", "top": "10%", "right": "1%" }
                ],
                "desktop:w<=1200": [
                    { "width": "728px", "height": "90px", "bottom": "0", "left": "50%" }
                ],
                "desktop:landscape:ar>=1.78": [
                    { "width": "200px", "height": "600px", "top": "5%", "left": "0" },
                    { "width": "200px", "height": "600px", "top": "5%", "right": "0" },
                    { "width": "970px", "height": "90px", "bottom": "0", "left": "50%" }
                ]
            },
            "<your_placement_here>": {
                "default": [
                    { "width": "728px", "height": "90px", "bottom": "0", "left": "50%" }
                ]
            },
            "<your_placement_here>": {
                "action": "hide"
            }
        }
    }
}
```

#### Game Code

{% tabs %}
{% tab title="Godot 3.x" %}

```gdscript
func _ready():
    Bridge.advertisement.connect("advanced_banners_state_changed", self, "_on_advanced_banners_state_changed")

    # Game lifecycle messages automatically trigger banners
    Bridge.platform.send_message(Bridge.PlatformMessage.GAME_READY)

func on_gameplay_started():
    Bridge.platform.send_message(Bridge.PlatformMessage.GAMEPLAY_STARTED)  # hides banners

func on_gameplay_stopped():
    Bridge.platform.send_message(Bridge.PlatformMessage.GAMEPLAY_STOPPED)  # shows banners

func on_shop_opened():
    Bridge.platform.send_custom_message("your_placement_here")  # shows banners

func on_shop_closed():
    Bridge.platform.send_custom_message("your_placement_here")  # hides banners

func show_banners_directly():
    Bridge.advertisement.show_advanced_banners("gameplay_stopped")

func hide_banners_directly():
    Bridge.advertisement.hide_advanced_banners()

func _on_advanced_banners_state_changed(state):
    print("Advanced Banners: ", state)
```

{% endtab %}

{% tab title="Godot 4.x" %}

```gdscript
func _ready():
    Bridge.advertisement.connect("advanced_banners_state_changed", Callable(self, "_on_advanced_banners_state_changed"))

    # Game lifecycle messages automatically trigger banners
    Bridge.platform.send_message(Bridge.PlatformMessage.GAME_READY)

func on_gameplay_started():
    Bridge.platform.send_message(Bridge.PlatformMessage.GAMEPLAY_STARTED)  # hides banners

func on_gameplay_stopped():
    Bridge.platform.send_message(Bridge.PlatformMessage.GAMEPLAY_STOPPED)  # shows banners

func on_shop_opened():
    Bridge.platform.send_custom_message("your_placement_here")  # shows banners

func on_shop_closed():
    Bridge.platform.send_custom_message("your_placement_here")  # hides banners

func show_banners_directly():
    Bridge.advertisement.show_advanced_banners("gameplay_stopped")

func hide_banners_directly():
    Bridge.advertisement.hide_advanced_banners()

func _on_advanced_banners_state_changed(state):
    print("Advanced Banners: ", state)
```

{% endtab %}
{% endtabs %}

### Configuration

Advanced Banners are configured in `playgama-bridge-config.json` under `advertisement.advancedBanners`.

```json
{
    "advertisement": {
        "advancedBanners": {
            "disable": false,
            "placementFallback": "main_menu",
            "main_menu": {
                "default": [
                    { "width": "300px", "height": "250px", "top": "10%", "right": "10%" }
                ]
            },
            "level_paused": {
                "action": "show",
                "default": [
                    { "width": "300px", "height": "250px", "top": "10%", "right": "10%" }
                ],
                "mobile:portrait": [
                    { "width": "100%", "height": "80px", "bottom": "0", "left": "0" }
                ],
                "desktop:landscape:w>1200": [
                    { "width": "160px", "height": "600px", "top": "10%", "left": "2%" },
                    { "width": "160px", "height": "600px", "top": "10%", "right": "2%" }
                ]
            },
            "level_resumed": {
                "action": "hide"
            }
        }
    }
}
```

#### General Options

| Parameter           | Type    | Default | Description                                                                           |
| ------------------- | ------- | ------- | ------------------------------------------------------------------------------------- |
| `disable`           | boolean | `false` | Disable Advanced Banners entirely, even if the platform supports them                 |
| `placementFallback` | string  | —       | Default placement to use when `show_advanced_banners()` is called without an argument |

#### Placement Configuration

Each key under `advancedBanners` (other than `disable` and `placementFallback`) defines a **placement**. A placement is identified by a string that matches either:

* A built-in platform message (e.g. `game_ready`, `level_paused`, `gameplay_started`)
* A custom message ID passed to `send_custom_message()`
* A string passed directly to `show_advanced_banners()`

Each placement contains:

| Property        | Type                 | Default  | Description                                                               |
| --------------- | -------------------- | -------- | ------------------------------------------------------------------------- |
| `action`        | `"show"` \| `"hide"` | `"show"` | Whether to show or hide banners when this placement is triggered          |
| `default`       | array                | —        | Fallback banner layout when no condition-based variant matches            |
| *condition key* | array                | —        | Banner layout for a specific set of conditions (see Condition Keys below) |

#### Banner Object

Each banner in the array is an object with CSS positioning values:

| Property | Type   | Description                           |
| -------- | ------ | ------------------------------------- |
| `width`  | string | CSS width (e.g. `"300px"`, `"100%"`)  |
| `height` | string | CSS height (e.g. `"250px"`, `"80px"`) |
| `top`    | string | CSS top offset (e.g. `"0"`, `"10%"`)  |
| `bottom` | string | CSS bottom offset                     |
| `left`   | string | CSS left offset                       |
| `right`  | string | CSS right offset                      |

You can define multiple banners per variant to show several ads simultaneously:

```json
"desktop:landscape": [
    { "width": "160px", "height": "600px", "top": "10%", "left": "2%" },
    { "width": "160px", "height": "600px", "top": "10%", "right": "2%" },
    { "width": "728px", "height": "90px", "bottom": "0", "left": "50%" }
]
```

### Condition Keys

Condition keys are colon-separated segments that describe when a variant should be used. The system evaluates all keys against the current environment and picks the best match.

#### Available Segments

| Segment          | Example                             | Description                                                                                                                          |
| ---------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Device type      | `mobile`, `desktop`, `tablet`, `tv` | Matches the current device type                                                                                                      |
| Orientation      | `portrait`, `landscape`             | Matches the current screen orientation                                                                                               |
| Width condition  | `w>600`, `w<=1024`, `w>=768`        | Matches against window width (or canvas width if `canvas` segment is present)                                                        |
| Height condition | `h>400`, `h<=900`                   | Matches against window height (or canvas height)                                                                                     |
| Aspect ratio     | `ar>1.5`, `ar>=1.78`, `ar<=1.0`     | Matches screen width/height ratio                                                                                                    |
| Canvas mode      | `canvas`                            | Use game canvas dimensions instead of window size for all `w`/`h`/`ar` conditions. If no canvas is found, the variant will not match |

#### Combining Segments

Combine segments with `:` to create compound conditions. All segments must match for the variant to be selected:

```json
{
    "mobile:portrait": [...],
    "mobile:portrait:w>400": [...],
    "desktop:landscape:w>1200:ar>=1.5": [...],
    "tablet:canvas:w>800": [...]
}
```

#### Priority Scoring

When multiple variants match, the one with the highest score wins:

| Segment Type                            | Score |
| --------------------------------------- | ----- |
| Device type (`mobile`, `desktop`, etc.) | +4    |
| Orientation (`portrait`, `landscape`)   | +2    |
| Canvas mode (`canvas`)                  | +1    |
| Each dimension/aspect ratio condition   | +1    |

If two variants have the same score, the one with **more segments** wins. If they also have the same number of segments, the one whose dimension/aspect ratio threshold is **closest to the actual value** takes priority.

**Example**: screen is 1300px wide, device is desktop

| Key                        | Matches?       | Score                        |
| -------------------------- | -------------- | ---------------------------- |
| `default`                  | yes (fallback) | -1                           |
| `desktop`                  | yes            | 4                            |
| `desktop:w>500`            | yes            | 4 + 1 = 5                    |
| `desktop:w>1200`           | yes            | 5 + higher specificity bonus |
| `desktop:landscape:w>1200` | yes            | 4 + 2 + 1 = 7                |
| `mobile:portrait`          | no             | —                            |
