Skip to main content
The Smoke on Damage plugin provides visual feedback when aircraft are damaged, emitting black smoke and simulating engine failures for enhanced realism.

Overview

When an aircraft’s health drops below a threshold, it begins emitting black smoke and suffers engine damage that disables the afterburner and prevents missile firing.
This plugin is implemented as a module (folder-based plugin) and serves as an example for creating more complex plugins that need multiple files.

Configuration

Configure smoke behavior in config.py:
# Enable planes smoking on low life
# If true, planes on life < SMOKE_LIFE will emit black smoke
# They will also have an engine breakdown, not being able to turn
# on afterburner. Also they won't be able to fire missiles
SMOKE_PLANE = True

# Planes smoking minimum life
SMOKE_LIFE = 5

Settings Explained

SettingTypeDescription
SMOKE_PLANEBooleanEnable/disable the entire smoke system
SMOKE_LIFEIntegerHealth threshold below which smoke appears
Setting SMOKE_LIFE too high (e.g., 50) will cause aircraft to smoke even with minor damage. Setting it too low (e.g., 1) means only critically damaged aircraft will smoke.

How It Works

Smoke Activation

The plugin monitors flight data packets and checks aircraft health:
def on_flight_data(self, data, player, message_to_client, message_to_server):
    """After the initial incoming flight packet, check whether
    the health is below the threshold, if so add smoke"""
    if SMOKE_PLANE and player.aircraft.life < SMOKE_LIFE:
        
        # Add smoke to the plane
        smoke_packet = FSNETCMD_AIRPLANESTATE(data).smoke()
        # Forward it on to the server
        message_to_server.append(smoke_packet)
        
        if not player.aircraft.damage_engine_warn_sent:
            player.aircraft.damage_engine_warn_sent = True
            # Warn the player
            message = "Your engine has been damaged! You can't turn on your afterburner!"
            message_to_client.append(FSNETCMD_TEXTMESSAGE.encode(message, True))
            
            message_to_client.append(FSNETCMD_AIRCMD.set_afterburner(player.aircraft.id, False, True))
        
        return False
    else:
        return True

Engine Damage Effects

When health drops below SMOKE_LIFE:
  1. Black smoke emission - Visual indicator of damage
  2. Afterburner disabled - Cannot engage afterburner
  3. Warning message sent - Player notified once
  4. Weapon restrictions - Cannot fire missiles
The warning message is only sent once per damage session to avoid spam. The flag damage_engine_warn_sent tracks this.

Repair and Recovery

Weapon Config Hook

When a player repairs or changes loadout:
def on_weapon_config(self, data, player, message_to_client, message_to_server):
    if ENABLED:
        player.aircraft.just_repaired = True
        if player.aircraft.get_initial_config_value("AFTBURNR") == "TRUE":
            message_to_client.append(FSNETCMD_AIRCMD.set_afterburner(player.aircraft.id, True, True))
    return True
Recovery process:
  1. Weapon config change detected (repair)
  2. just_repaired flag set (important for anti-cheat)
  3. If aircraft has afterburner capability, it’s re-enabled
  4. Damage warning flag reset

Player Experience

Visual Feedback

Players and observers will see:
  • Black smoke trail from damaged aircraft
  • Smoke intensity remains constant below threshold
  • Smoke stops when aircraft is repaired or health recovers

Warning Message

On first damage below threshold:
Your engine has been damaged! You can't turn on your afterburner!

Example Configurations

High Realism (Strict)

SMOKE_PLANE = True
SMOKE_LIFE = 10
Aircraft smoke with even moderate damage, emphasizing careful flying.

Balanced Gameplay

SMOKE_PLANE = True
SMOKE_LIFE = 5
Default setting - smoke appears when critically damaged.

Critical Damage Only

SMOKE_PLANE = True
SMOKE_LIFE = 2
Only severely damaged aircraft smoke, allowing aggressive combat.

Disabled

SMOKE_PLANE = False
Disabling smoke doesn’t affect other damage mechanics - aircraft still take damage normally.

Technical Implementation

Plugin Structure

This is a folder-based plugin:
plugins/smoke_on_damage/
├── __init__.py
└── Plugin.py

Registered Hooks

def register(self, plugin_manager):
    self.plugin_manager = plugin_manager
    self.plugin_manager.register_hook('on_flight_data', self.on_flight_data)
    self.plugin_manager.register_hook('on_weapon_config', self.on_weapon_config)
Hooks used:
  • on_flight_data - Monitor health and emit smoke
  • on_weapon_config - Handle repairs and restore afterburner

Smoke Packet Generation

The smoke effect is generated by modifying the flight state packet:
smoke_packet = FSNETCMD_AIRPLANESTATE(data).smoke()
This creates a modified packet that includes smoke emission data.

Integration with Other Features

Anti-Cheat System

The just_repaired flag is critical for the anti-cheat system:
if player.aircraft.prev_life < player.aircraft.life and player.aircraft.prev_life != -1 and not player.aircraft.just_repaired:
    # Health hack detection
This prevents false positives when players repair legitimately.

G-Force Limiter

Combines well with the G-Limiter:
  • G-limiter causes damage
  • Smoke plugin provides visual feedback
  • Creates immersive damage progression

Troubleshooting

Smoke not appearing?
  1. Check SMOKE_PLANE = True in config.py
  2. Verify health is actually below SMOKE_LIFE threshold
  3. Enable DEBUG logging to see plugin activity
  4. Ensure plugin is loaded (check startup logs)

Creating Similar Plugins

This plugin demonstrates:
  • Folder-based plugin structure
  • Multiple hook registration
  • State tracking across packets
  • Client-specific messaging
  • Packet modification and forwarding
Use it as a template for your own complex plugins!

Build docs developers (and LLMs) love