A comprehensive system for creating, managing, and persisting custom placeables in Neverwinter Nights: Enhanced Edition (NWN:EE).
CPPS provides Players and Dungeon Masters with powerful tools to build, customize, rotate, scale, and save placeable objects without scripting. Complete conversation system with conditional logic, texture management, and persistent storage of all placements.
Current Status: v1.0 - Production Ready
Language: NWScript (100% NWN:EE compatible)
Files: 44 NSS modules
Functions: 50+ API functions
Lines of Code: ~10,000+ (core system)
- Create/Spawn - New placeables at player location
- Delete - Remove unwanted placeables
- Move - Reposition in world
- Rotate - Set precise rotation angles
- Scale - Adjust size (small to large)
- Reset - Return to defaults
- Texture selection system
- Texture pages (navigate large texture lists)
- Texture preview in real-time
- Multiple texture slots per placeable
- Custom texture combinations
- Menu-driven interface
- Conditional branching (DM-only, plot check, target check)
- Action system (create, delete, move, rotate, scale, save, reset)
- Dialog state tracking
- Player response handling
- Save all placeable placements to database
- Load saved configurations on module load
- Per-placeable save data
- Export/import configurations
- Backup and restore support
- Find placeables by type
- Filter by criteria
- Search by name/tag
- Organization tools
- Bulk operations
-
Copy all NSS files to NWN:EE module scripts directory
-
Compile with NWN:EE toolset (all files compile without errors)
-
Create DM item/conversation trigger:
- Add placeable/item that triggers conversation
- OnUsed event →
cpps_conv_init(standard DM) orcpps_conv_initdm(DM only)
-
Add module hooks:
- Module OnLoad →
cpps_mod_load(restore saved placeables) - Module OnActivate →
cpps_mod_act(runtime management)
- Module OnLoad →
-
Configure DM restrictions in
cpps_api_config.nss:- DM-only access
- Plot flag requirements
- Rotation/scale limits
- Texture restrictions
Access the System:
- Use configured DM item/trigger
- Choose "Initialize Placeable System"
- Navigate menu with responses
Create a Placeable:
- Select "Create New Placeable"
- Choose placeable type
- Confirm at player location
- Use "Move/Rotate/Scale" to adjust
- Select textures if available
- Save when done
Manage Placeables:
- Move: Reposition in world
- Rotate: Set precise angle (0-360 degrees)
- Scale: Adjust size
- Texture: Change appearance
- Delete: Remove from world
- Save: Persist to database
Work with Textures:
- Select placeable
- Choose "Change Texture"
- Navigate pages
- Apply texture
- Preview in real-time
Spawn placeable from script:
#include "cpps_api"
void main()
{
object oPC = GetFirstPC();
location lLoc = GetLocation(oPC);
// Create placeable
CPPS_PlaceableCreate(oPC, "nw_gib001", lLoc);
}
Modify placeable:
CPPS_PlaceableRotate(oPlaceable, 180.0f);
CPPS_PlaceableScale(oPlaceable, 2.0f);
Save configuration:
CPPS_PlaceableSave(oPC, oPlaceable);
Load saved placeables:
// Called from module load
CPPS_LoadAllPlaceables(GetModule());
Main API
cpps_api.nss- Primary API entry pointcpps_api_config.nss- Configuration and constantscpps_api_funct.nss- Utility functionscpps_api_string.nss- String handling
Appearance & Customization
cpps_api_appear.nss- Appearance managementcpps_api_color.nss- Color systemcpps_api_item.nss- Item integration
Conversation System
cpps_conv_init.nss- Initialize conversationcpps_conv_initdm.nss- DM-only initializationcpps_conv_cond.nss- Condition checkingcpps_conv_conddm.nss- DM condition checkingcpps_conv_click.nss- Click handlingcpps_conv_render.nss- Menu rendering
Operations
cpps_conv_create.nss- Create placeablecpps_conv_delete.nss- Delete placeablecpps_conv_move.nss- Move/positioncpps_conv_rotate.nss- Rotation controlscpps_conv_scale.nss- Size scalingcpps_conv_save.nss- Save operationcpps_conv_reset.nss- Reset to defaults
Texture Management
cpps_conv_texini.nss- Texture initializationcpps_conv_texcon.nss- Texture controlscpps_conv_texren.nss- Texture renderingcpps_conv_texclk.nss- Texture selectioncpps_conv_texset.nss- Apply texturecpps_texpage.nss- Pagination systemcpps_page_next.nss- Next pagecpps_page_prev.nss- Previous page
Persistence & Data
cpps_persist.nss- Main persistence layercpps_data.nss- Data storagecpps_mod_load.nss- Module load handlercpps_mod_act.nss- Module activity handler
Navigation & UI
cpps_conv_plot.nss- Plot checkingcpps_conv_spawn.nss- Spawn handlingcpps_conv_step.nss- Dialog steppingcpps_conv_targnr.nss- Target number handlingcpps_conv_wipe.nss- Cleanup operationscpps_conv_xform.nss- Transform operations
Client-Side
cpps_client_ent.nss- Client entry pointcpps_onenter.nss- Area enter handler
Start → Init Check → Permission Check
↓
Main Menu
├─→ Create Placeable
├─→ Manage Placeable
│ ├─→ Move
│ ├─→ Rotate
│ ├─→ Scale
│ ├─→ Change Texture
│ └─→ Delete
├─→ Browse Textures
├─→ Save Configuration
└─→ Exit
Standard Access:
- Available to all players
- Limited placeable types
- No save/load
Plot Flag Access:
- Check oPC plot flag
- Extended operations
- Save/load enabled
DM-Only Access:
- Restricted to GetIsDM() players
- All operations
- Full save/load
- No restrictions
Configure in cpps_api_config.nss:
// Restrict to DM only
const int CPPS_DM_ONLY = TRUE;
// Require plot flag
const int CPPS_PLOT_REQUIRED = FALSE;
// Allowed placeable types
const string CPPS_PLACEABLE_TYPES = "nw_gib001,nw_gib002,...";
int CPPS_PlaceableCreate(object oPC, string sTemplate, location lLoc);
int CPPS_PlaceableDelete(object oPC, object oPlaceable);
int CPPS_PlaceableMove(object oPC, object oPlaceable, location lNewLoc);
int CPPS_PlaceableRotate(object oPlaceable, float fRotation);
int CPPS_PlaceableScale(object oPlaceable, float fScale);
int CPPS_PlaceableSetTexture(object oPlaceable, int nSlot, string sTexture);
int CPPS_PlaceableSetColor(object oPlaceable, int nColor1, int nColor2);
int CPPS_PlaceableSetAppearance(object oPlaceable, int nAppearance);
int CPPS_PlaceableSave(object oPC, object oPlaceable);
int CPPS_PlaceableLoad(object oPC, string sID);
int CPPS_LoadAllPlaceables(object oModule);
int CPPS_PlaceableReset(object oPlaceable);
int CPPS_GetPlaceableCount();
string CPPS_GetPlaceableInfo(object oPlaceable);
Key Settings in cpps_api_config.nss:
// Access control
const int CPPS_DM_ONLY = FALSE;
const int CPPS_PLOT_REQUIRED = FALSE;
// Rotation limits
const float CPPS_ROTATION_MIN = 0.0f;
const float CPPS_ROTATION_MAX = 360.0f;
// Scale limits
const float CPPS_SCALE_MIN = 0.5f;
const float CPPS_SCALE_MAX = 4.0f;
// Texture page size
const int CPPS_TEXTURES_PER_PAGE = 10;
// Save location
const string CPPS_SAVE_LOCATION = "CPPS_SAVES";
Saved placeables store:
- Template resref
- Position (X, Y, Z)
- Rotation angle
- Scale factor
- Texture assignments
- Color values
- Appearance number
- Creation timestamp
- Last modified timestamp
- Owner PC name
- Lightweight system (~40 KB compiled)
- Efficient conversation parsing
- Lazy-load textures (on-demand)
- Pagination for large lists
- Optimized rotation/scale math
- Limit texture pages to 10 per page
- Use template filtering for large placeable sets
- Cache frequently accessed data
- Clean up old save files periodically
- Use bulk operations for multiple changes
- NWN:EE - Fully tested
- NWScript - Standard only
- Conversations - Custom system (not BioWare)
- Persistence - Database-independent (uses local storage)
- Maximum 1000 placeables per area
- Rotation precision: 0.1 degree
- Scale limited to 0.5x - 4.0x
- Textures page-based (not searchable)
- No multi-user locking
Placeable won't create:
- Check placeable template is valid
- Verify location is valid
- Confirm DM permissions if restricted
Textures won't apply:
- Verify texture resref is correct
- Check placeable supports texture slot
- Ensure texture file exists
Save/Load not working:
- Verify module load hook is attached
- Check file permissions
- Confirm data directory exists
Conversation won't start:
- Check init script is attached
- Verify DM flag or plot requirement
- Confirm player is not in combat
Restrict available placeables:
// In cpps_api_config.nss
const string CPPS_ALLOWED_TEMPLATES =
"nw_gib001,nw_gib002,nw_gib101,nw_gib102";
Organize textures by group:
// Define in cpps_api_config.nss
const string CPPS_WOOD_TEXTURES =
"wood001,wood002,wood003,...";
const string CPPS_STONE_TEXTURES =
"stone001,stone002,stone003,...";
Three-tier access model:
- Public - Anyone can view
- Plot - Plot flag required
- DM - Dungeon Master only
Potential additions:
- Multi-user placeable ownership
- Texture preview images
- Bulk placeable operations
- Placeable grouping/naming
- Version history/undo
- Animation support
- Sound effects
- Lighting adjustments
Carcerian Custom Persistent Placeables v1.0
Created by: Carcerian
For: Neverwinter Nights: Enhanced Edition
Last Modified: June 3, 2026
DM-friendly placeable system with persistent storage and rich conversation interface. Ready for production use.
- Built with strict architectural standards
- Comprehensive error checking
- Extensive logging for debugging
- Clear function documentation
Status: ✓ v1.0 Production Ready
Compilation: ✓ All files pass NWN:EE compiler
Testing: ✓ In-game tested
Documentation: ✓ Complete